【Rails+Vue】jwtによるトークン認証

認証におけるjwtのメリット

  • CORSなどの制約がない
    異なるドメイン間の通信を拒否する制約にかからない
  • スケーラブルである
    cookie認証の場合はセッションを保持する別のサーバーやDBが必要になる。jwt認証の場合はアプリケーションサーバーのみで認証ができるためスケーラブルである。

jwt(json web token)

gem 'jwt'で実装する。

gem 'jwt'
require 'jwt'

# エンコード
payload = { data: 'test' }
token = JWT.encode payload, key

puts token
# eyJhbGciOiJub25lIn0.eyJkYXRhIjoidGVzdCJ9.

# デコード
decoded_token = JWT.decode token, key

puts decoded_token
# Array
# [
#   {"data"=>"test"}, # payload
#   {"alg"=>"none"} # header
# ]
secret_key_baseを用いたエンコード/デコード
# エンコード
token = JWT.encode payload, Rails.application.credentials.secret_key_base

# デコード
decoded = JWT.decode token, Rails.application.credentials.secret_key_base

Rails+Vueにおけるjwt認証

1 ログイン成功時にトークンを発行しフロントエンドに渡す

class AuthenticationsController < ApplicationController
  def create
     # ログイン成功
     payload = {
         user_id: ユーザーID
         exp: 有効期限 }
     token = JWT.encode payload, Rails.application.credentials.secret_key_base
     render json: { token: token }
  end

2 フロントエンド側でトークンをリクエストヘッダーに含める

axios.defaults.headers.common['Authorization'] = `Bearer ${res.token}`

3 リクエストごとにトークン認証を行う

# リクエストヘッダーからトークンを抽出する
header = request.header['Authorization']

pattern = /^Bearer /
token = header.gsub(pattern, '') if header&.match(pattern)

# トークンをデコードしペイロードを取得
payload, = JWT.decode token, Rails.application.credentials.secret_key_base

# ペイロードのユーザーIDでユーザーを照会する
User.find_by(id: payload['user_id'])