はじめに
よくあるjwt 認証についてそこらたりをまとめました
前提
Railsのjwt等を使用します。
主な流れとしては以下です
login, signupが成功すると同時にRails側でCookieにaccess_tokenをセット。
frontend側からはcookieに格納しておき、api通信時にcookieから取り出し
リクエストヘッダのAuthorizationヘッダにBearerトークンとして添付し送る
backend側はそのBearerトークンを読み取り、decodeして
中身を読み取り、中に入っているuserIdを取得してUserを取得できたら認証完了
コード
今回はフロントから想定通りの出力が渡ってくる前提で行います。
まずapplication_controller.rbにおいてauthenticate_userを実装
成功時、インスタンス変数として@current_userを格納
access_tokenの正常チェックはjwt gemのdecodeが行う。
def authenticate_user!
token = extract_token
return render_error("認証に失敗しました", :unauthorized) unless token
payload = Infrastructure::JwtService.decode(token)[0]
@current_user = User.find(payload['user_id'])
end
def extract_token
request.headers['Authorization']&.split(' ')&.last
end
module Infrastructure
class JwtService
class TokenExpiredError < StandardError; end
class InvalidTokenError < StandardError; end
def self.encode(payload)
payload[:exp] = 1.hours.from_now.to_i
JWT.encode(payload, Rails.application.credentials.secret_key_base, 'HS256')
end
def self.decode(token)
JWT.decode(token, Rails.application.credentials.secret_key_base, true, { algorithm: 'HS256' })
rescue JWT::ExpiredSignature
raise TokenExpiredError.new("トークンの有効期限が切れています")
rescue JWT::DecodeError
raise InvalidTokenError.new("トークンが無効です")
end
end
end
簡易的ですが、こんな感じです。
例外補足は全てapplication_contrllerのrescue_fromで行います。
終わりに
環境ごとにcredentialsを使っていたのですが、一度developmentとか作ってしまうとdefaultのcredentialsを読む術って無くなるんすね。
読み出す優先順序としては環境別のものが優先されるとは聞いてましたが、環境別のものを作ると勝手にmergeしてくれたりしないんすね。
それで朝詰まったので良い勉強となりました。