RailsでJWT認証

2018-07-09T00:00:00+09:00 Ruby Rails JWT

RailsでのWeb API呼び出しにJWT認証を使ってみる

※あくまでJWTを使ってみた的な感じなので本当ならknock等を利用したりだとかdeviseなどと連携出来るのを使うべきなんでしょうけど今回はそういう趣旨じゃないので

Gemfile

単純に

gems "jwt"

を追加するだけ

config/routes.rb

Rails.application.routes.draw do
  get "/user", to: "auth#user"
  post "/auth", to: "auth#auth"
end

app/controllers/auth_controller.rb

require "jwt"

# ApplicationController = ActionController::API
class AuthController < ApplicationController
  before_action :authenticate, :except => [:auth]

  def user
    render json: @user
  end

  def auth
    data = { userid: params[:userid] }
    render plain: JWT.encode(data, Rails.application.secrets.secret_key_base, "HS256")
  end

  private

  def authenticate
    if request.headers["Authorization"].present?
      token = request.headers['Authorization'].split(' ').last
      @user = JWT.decode(token, Rails.application.secrets.secret_key_base, true, { algorithm: "HS256" })[0]
    else
      render json: { status: "ERROR", message: "Not Authorized" }
    end
  end

end

要は/userのAPIをコールするにはAuthorizationヘッダーにJWTトークンを仕込んでリクエストしなければならない。でそのトークン自体は/authから取得する事が出来るので、それをリクエストした結果をAuthorizationヘッダーに指定した上でリクエストする事でAPIをコールする事が出来るようになる感じ。でそのチェックをbefore_actionを使って呼び出してるだけ

public/index.html

JavaScript部分だけ抜粋

function getToken(userid) {
  const token = localStorage["token"];

  if (token) {
    return new Promise(resolve => {
      resolve(token);
    });
  } else {
    return new Promise(resolve => {
      fetch("/auth",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json"
          },
          body: JSON.stringify({ "userid": userid })
        }
      ).then(res => {
        res.text().then(token => {
          localStorage["token"] = token;
          resolve(token);
        });
      });
    });
  }
}

function getUser(token) {
  return new Promise(resolve => {
    fetch(
      "/user",
      {
        headers: {
          "Authorization": token
        }
      }
    ).then(res => {
      res.json().then(data => {
        resolve(data);
      });
    });
  });
}

getToken("hoge").then(token => {
  getUser(token).then(data => {
    console.log(data);
  });
});

以上。誓いうちにknockだとか他の認証系モジュールとかも使っての検証とかやってみる予定

参考: https://www.pluralsight.com/guides/token-based-authentication-with-ruby-on-rails-5-api

GraphQLスキーマを定義して利用する方法 graphql.jsを使ってみた