3
2

More than 3 years have passed since last update.

Knock gemを用いてJWTで2種類のユーザーを認証する方法

Posted at

RailsのAPIでJWTを使って単一のuserの認証システムを作っていましたが、途中でuser -> workerとなり、新たにrecruiterというのが出てくることになりました。
JWTの認証にはKnockというgemを使っていましたが、単一のuserに対して認証することが前提に作られていたので、少しカスタマイズします。

modelの変更点

新たに出てきたrecruiterに関しても公式の手順に従ってtoken controllerなどを作成しておきます。
公式ページにも載っているように、カスタマイズするにはこの2つのmethodをいじればいいです。

まずKnockが生成するJWTの形を変更します。
defaultではsubというkeyにidが入っていますが、さらにclassを追加してあげることで、JWTを持っているのがworkerなのかrecruiterなのかという判別ができるようになります。


class User < ActiveRecord::Base
  def to_token_payload
    # Returns the payload as a hash
    { sub: id, class: self.class.to_s }
  end
end

ここではworker or recruiterを探す時にJWTにclassが入っているかを確認するように変更しています。


class User < ActiveRecord::Base
  def self.from_token_payload payload
    # Returns a valid user, `nil` or raise
    # e.g.
    # defaultではこうなっている
    # self.find payload["sub"]

    find payload['sub'] if payload['class'] && payload['class'] == to_s
  end
end

認証メソッドの変更点

defaultのKnockではworkerに対して、認証するにはauthenticate_workerを使えば認証が動くようになっていました。
ここではrecruiterも追加されたので、2つを認証する方法について解説します。

実装は以下のようになります。
authenticate_userというメソッドの内部でJWTの中身のclassに応じて条件分岐して、authenticate_xxxメソッドを実行するようにします。

application_controller.rb

class ApplicationController < ActionController::API
  include Knock::Authenticable
  before_action :authenticate_user

  def authenticate_user
    class_name = Knock::AuthToken.new(token: token).payload['class']
    return unless class_name

    case class_name.constantize
    when Worker
      authenticate_worker
    when Recruiter
      authenticate_recruiter
    end
  end

もし、あるcontrollerだけはrecruiterからは操作できないようにしたい時があれば、以下のようにします。

xxx_controller

class XxxController < ActionController::API
  skip_before_action :authenticate_user
  before_action :authenticate_worker
end
3
2
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
3
2