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