0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【JWT】復号後データのハッシュキーに関するエラー

Last updated at Posted at 2024-01-07

はじめに

私がJWT認証で発生したちょっとしたエラーを紹介します。

JWTとは

JWT(JSON Web Token)は、認証情報をJSON形式で安全に交換できる方法のことです。

詳しい説明は以下の記事を参考にしてください。

実行内容

Postmanでhttp://127.0.0.1:3000/api/usersにGETメソッドを送り、全ユーザー情報の取得。

※Requestのheaderに以下の認証情報を設定しています。
 キー:Authorization 値:Bearer {{jwt token}} 

routes.rb
Rails.application.routes.draw do
  namespace :api do
    resources :users

#     ・
#	  ・
#	  ・

  end
end
users_controller.rb
module Api
	class UsersController < ApplicationController
		include JwtAuthenticator
	  before_action :jwt_authenticate, only: %i[index]

	  def index
	    users = User.all.map { |user| user.slice(:id, :email) }
	    render json: { users: users }
	  end

#	  ・
#	  ・
#	  ・

	end
end
jwt_authenticator.rb
module JwtAuthenticator
  require "jwt"

  SECRET_KEY_BASE = Rails.application.secrets.secret_key_base

  def jwt_authenticate
    render json: { error: "認証情報が不足しています。" }, status: :unauthorized if request.headers["Authorization"].blank?
    encoded_token = request.headers["Authorization"].split("Bearer ").last
    payload = decode(encoded_token)
    @user = User.find_by(id: payload[:user_id])
    render json: { error: "認証に失敗しました。" }, status: :unauthorized if @user.blank?
    @user
  end

  # 暗号化処理
  def encode(user_id)
    expires_in = 1.month.from_now.to_i
    preload = { user_id: user_id, exp: expires_in }
    JWT.encode(preload, SECRET_KEY_BASE, 'HS256')
  end

  # 復号化処理
  def decode(encoded_token)
    decoded_dwt = JWT.decode(encoded_token, SECRET_KEY_BASE, true, algorithm: 'HS256')
    decoded_dwt.first
  end
end

エラー内容

以下のresponseボディが返ってきました。

{
    "error": "認証に失敗しました。"
}

原因

データの復号後、payload[:user_id]のようにシンボルでキーを指定していたことが原因でした。

payload = decode(encoded_token)
@user = User.find_by(id: payload[:user_id])

jwtはJSON形式のデータを暗号化・復号化するため、暗号化する際にデータを一度JSON形式に変換しています。JSON形式は文字列のみで構成されるため、シンボルをキーとしていた場合、文字列のキーに置き換えられてしまいます。暗号化前と復号後のpreloadは以下のとおりです。

暗号化前:preload = { user_id: user_id, exp: expires_in }

復号化後:preload = { "user_id" => user_id, "exp" => expires_in }

解決策

解決策としては、キーを文字列からシンボルに変換させる方法、キーを文字列で指定する方法の2種類あります。

解決策1:キーを文字列からシンボルに変換

transform_keys(&:to_sym)で文字列からシンボルに変換することが出来ます。

payload = decode(encoded_token).transform_keys(&:to_sym)
@user = User.find_by(id: payload[:user_id])

解決策2:キーを文字列で指定

:user_idではなく”user_id”で指定してあげることで、復号後データを変換しなくてもキーを指定することが可能です。

payload = decode(encoded_token)
@user = User.find_by(id: payload["user_id"])

まとめ

  • JWT認証はJSON形式のデータを暗号化していること。
  • JSON形式はシンボルで記載出来ないこと。

参考文献

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?