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?

More than 1 year has passed since last update.

device_token_authのコードリーディング

Posted at

実務でdevice_token_authを扱うことになりました。
理解を深めるために、ログイン認証時に実行されるsessions_controllerのcreateアクションをコードリーディングしてみました。

sessions_controllerのcreateアクションとは?

ログイン認証時に実行されるアクションです。
createアクションの処理のはざっくり以下のような流れで構成されています。

  1. 認証対象のレコードの検索
  2. 認証処理
    1. 認証対象のレコードが存在し、認証可能な状態にある場合
    2. 認証対象のレコードが存在するが、認証可能な状態にない場合
    3. 1と2いずれにも当てはまらない場合

※createアクション内で呼び出される他controllerや他moduleの処理は深追いして解説はしません。

1. 認証対象のレコードの検索

      if field = (resource_params.keys.map(&:to_sym) & resource_class.authentication_keys).first
        q_value = get_case_insensitive_field_from_resource_params(field)

        @resource = find_resource(field, q_value)
      end

field, q_valueにはそれぞれ以下の値が設定されます。そして、これらの変数を引数にfind_resourceを呼び出して、認証対象のレコードを検索します。

  • field:認証用のカラム(例:email, login_id)
    resource_params(認証に関するリクエストパラメータ)のキーとdeviceで設定したauthentication_keys(認証用のカラム名)の重複値が格納される。
  • qvalue:resource_paramsのうち、fieldのキーに対するvalue
    この時valueをそのまま格納するわけではなく、deviceの設定でcase_insensitive_keys(大文字小文字を区別しない)もしくはstrip_whitespace_keys(空白を無視する) にfieldのキーが指定されている場合は、適切な加工を実施したうえで格納される。

2. 認証処理

認証処理は3つのパターンに分かれます。

1. 認証対象のレコードが存在し、かつそれが認証可能な状態にある場合

認証可能な状態とは、アカウントがロックされておらず、かつメール認証等のアカウント認証も完了している状態を指します。

      if @resource && valid_params?(field, q_value) && (!@resource.respond_to?(:active_for_authentication?) || @resource.active_for_authentication?)
        valid_password = @resource.valid_password?(resource_params[:password])
        if (@resource.respond_to?(:valid_for_authentication?) && !@resource.valid_for_authentication? { valid_password }) || !valid_password
          return render_create_error_bad_credentials
        end

        create_and_assign_token

        sign_in(@resource, scope: :user, store: false, bypass: false)

        yield @resource if block_given?

        render_create_success

冒頭の条件部分にてvalid_params?(field, q_value)はリクエストパラメータにpasswordキーが存在することをチェックします。

valid_password にはパスワードの認証結果がbooleanで保持されます。

パスワード認証に失敗した場合は、認証情報が正しくない旨のエラーメッセージを返却します。

認証に成功した場合は、create_and_assign_tokenでトークンを生成し、ログイン処理を実行します。
最後にrender_create_successでレスポンスとして、トークン情報や有効期限等をクライアントに返却します。

補足
valid_for_authenticationや後述のactive_for_authenticationはざっくり「そのアカウントがロックされておらず、かつメール認証等のアカウント認証も完了しているか」を判定するインスタンスメソッドと解釈ください。いずれもlib/devise/models/authenticatable.rbで定義されたメソッドですが、lockableやconfirmableでオーバーライドされており、ブラックボックスな形になっています。

2. 認証対象のレコードが存在するが、認証可能な状態にない場合

対象のレコードは存在するが、ロックされている、メールでのアカウント認証が済んでいない等認証可能な状態になっていない場合の処理です。

      elsif @resource && !Devise.paranoid && !(!@resource.respond_to?(:active_for_authentication?) || @resource.active_for_authentication?)
        if @resource.respond_to?(:locked_at) && @resource.locked_at
          render_create_error_account_locked
        else
          render_create_error_not_confirmed
        end

ロックされている場合はその旨のエラーを、それ以外の場合はアカウントが未認証である旨のエラーを返却します。

!Devise.paranoidはDeviseの設定でparanoidモードが無効になっていることを指します。説明を簡略化するために省きましたが、レコードが存在しそれが認証可能な状態にない場合でも、paranoidモードが有効な場合は3の分岐に入ります。

3. 1と2いずれにも当てはまらない場合

      else
        hash_password_in_paranoid_mode
        render_create_error_bad_credentials
      end

認証情報が正しくない旨のエラーメッセージを返却します。
hash_password_in_paranoid_modeはparanoidモードが有効な場合に実行されるセキュリティ対策(タイミング攻撃への対策)の処理だそうです。(paranoidモードについては詳しくないため、別記事にまとめたいと思います。)

今後

createアクションの大まかな流れは以上です。今後createアクション内で呼び出されている処理も気が向いたら読んでいきたいと思います。

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?