🦔

deviseについて

2022/08/31に公開約5,100字

ZENKIGEN「harutaka」開発チームの藤井です。私が開発に携わっている採用DXサービス「harutaka」のログイン認証等で用いられているdeviseがどういったモノなのか理解するために、Rubyの勉強も兼ねてdeviseについて調査をしたので、その知見をシェアしたいと思います。

https://harutaka.jp/

deviseについて

deviseとはrailsで作ったwebアプリケーションに簡単に認証機能を実装できるgem
のことです。

ログインやサインアップなどのログイン機能を1から構築するのはかなり大変ですが、deviseを利用することで簡単に実装することが出来ます。

具体的にdeviseでは以下のような機能を実装することが出来ます。

  • サインアップ機能
  • サインイン機能
  • アカウント編集機能
  • パスワード変更機能
  • メール認証機能
  • アカウント凍結機能

💡 deviseの読み方は「デヴァイズ」
装置を意味するdeviceと混合しないように

deviseとUserモデル

deviseは、導入時に認証用モデルを作成することできます。

認証用モデル(テーブル)に作成されるカラムは以下の通り。

+------------------------+--------------+------+-----+---------+----------------+
| Field                  | Type         | Null | Key | Default | Extra          |
+------------------------+--------------+------+-----+---------+----------------+
| id                     | bigint       | NO   | PRI | NULL    | auto_increment |
| email                  | varchar(255) | NO   | UNI |         |                |
| encrypted_password     | varchar(255) | NO   |     |         |                |
| reset_password_token   | varchar(255) | YES  | UNI | NULL    |                |
| reset_password_sent_at | datetime     | YES  |     | NULL    |                |
| remember_created_at    | datetime     | YES  |     | NULL    |                |
| created_at             | datetime(6)  | NO   |     | NULL    |                |
| updated_at             | datetime(6)  | NO   |     | NULL    |                |
+------------------------+--------------+------+-----+---------+----------------+

DBを確認すると、usersテーブルに上記のカラムが存在していることが確認できました。

このことから、弊社でもUserモデルを認証用モデルとして取り扱っていることが分かりました。

deviseの仕事

deviseがやってくれる仕事は大きく分けると次の3つがあると知りました。

  1. ユーザー認証の基本的なメソッドの付与
  2. 認証用モデルごとのhelper系メソッドの作成
  3. モジュールごとに必要な仕事

引用:Deviseのモヤモヤを解消して快適なRailsライフを送ろう!

ユーザー認証の基本的なメソッドの付与

ユーザー認証の機能に必要な基本的なメソッドを付与してくれます。

メソッド名 機能 harutakaで使用
sign_in すでに認証されているユーザーでサインインする(ログイン)
sign_out 特定のユーザーまたはスコープをサインアウトする(ログアウト)

認証用モデルごとのhelper系メソッドの作成

認証用モデルの名前が入ったヘルパーメソッドを作成してくれます。

(以下、認証用モデルをUserとします)

メソッド名 機能 harutakaで使用
authenticate_user! ユーザーの認証を行い、ログイン済ユーザーのみにアクセスを許可する
user_signed_in? ユーザーがログインしているかどうか
current_user 現在、ログインしているユーザーのモデルインスタンスを取得する
user_session ユーザーのセッション情報を設定・取得

モジュールごとに必要な仕事

それぞれのモジュールの機能を実現するために必要な仕事をしてくれます。
ここで言うモジュールとは、ユーザー認証に関連する「機能」のまとまりを指します。

モジュール名 機能 harutakaで使用
database_authenticatable DBに保存するパスワードの暗号化を行う
registerable ユーザーの登録(サインアップ)を行う
recoverable ユーザのパスワードをリセットできる
rememberable cookieを使用し、ユーザ情報を保持する
trackable サインイン回数・時刻・IPアドレスを保存する
validatable メールアドレスとパスワードのバリデーションをする
confirmable サインインをした際に既にアカウントが登録されているかどうかを確認できる
lockable 指定された回数サインインを失敗するとアカウントをロックする
timeoutable 一定時間でセッションを削除する
omniauthable OmniAuthのサポートをする

deviseとwarden

deviseはwardenという認証周りのRackミドルウェアをベースにしていることが分かりました。

Rackミドルウェアについては、以下記事が大変参考になりました。

Rack入門 Rack Middleware編 (3/3)

ヘルパーメソッドの一つであるcurrent_userの内部を見てみると、以下のようなソースになっています。

def current_#{mapping}
   @current_#{mapping} ||= warden.authenticate(scope: :#{mapping})
end

mappingの部分は認証モデルの名前が入ってくるのですが、warden.authenticate(scope: :#{mapping})とwardenのauthenticateメソッドが呼び出されています。

wardenのauthenticateメソッドで行われている処理は以下となっています。

1.usersプロパティに値が入っていればそれを返す

2.sessionにuserのデータがあるかを探しに行く。データがあればdeserializeして、usersプロパティにセットして、返す。

3.有効なstrategiesを実行し、認証が成功したら、そのuserを返す

  • 有効かどうかの判定の多くはreques.paramのデータに認証に必要なkeyがあるかで判断されるので、認証用のアクション以外では基本的に有効とはならない
  • 例えばdatabase_authenticatable strategyでは、emailのkeyがあるかなど。

引用:deviseの調査メモ

すなわち、wardenが認証の仕組みを担っており、その仕組みをrailsに実装する役割がdeviseであると分かりました。

排他ロックの危険性について

調べていく中でdeviseを使うことで排他ロックを引き起こす危険性があると知りました。

trackableモジュールでは、ユーザーのサインイン回数や時刻を記録していますが、同時に同一のユーザーでアクセスを行うと排他ロックが発生してしまいます。

以下は、trackableモジュールによって実行されるSQLです。

UPDATE users SET last_sign_in_at = '2022-07-03 04:55:04',
current_sign_in_at = '2022-07-03 04:55:05',
sign_in_count = 323,
updated_at = '2022-07-03 04:55:05'
WHERE users.id = 1

その他のモジュールも特定の条件付きですが、同一ユーザーを流用することで排他ロックが発生してしまいます。

基本的に同一ユーザーを複数人で使う回すことは無いとは思いますが、こういった危険性があることを念頭に置いておいた方が良さそうです。

まとめ

deviseは便利な反面ブラックボックス感がありましたが、どういった仕組みで認証をしているかを学ぶ事ができて、deviseとは何かを知る事ができました。

また、今回の調査でharutakaとdeviseにどういう繋がりがあるのか知ることが出来たので、自分の携わっているサービスの仕組みについての理解も深める事ができました。

参考&引用

https://zenn.dev/kitabatake/articles/start-to-like-the-devise

https://github.com/heartcombo/devise

https://www.bigbinary.com/blog/skip-devise-trackable-module-for-api-calls

https://qiita.com/yoshi_4/items/a3ae25ee3368282f5b88

https://nekorails.hatenablog.com/entry/2021/03/18/110200

https://zenn.dev/kitabatake/scraps/e319ecf7fc0aaf9c5ec0

https://nekorails.hatenablog.com/entry/2018/10/27/172832

https://qiita.com/nishio-dens/items/8011842f50995f46eafe

https://qiita.com/jnchito/items/3884f9a2ccc057f8f3a3

Discussion

ログインするとコメントできます