deviseでアカウントロックを後から追加する

deviseRailsアプリに認証機能を提供してくれる素晴らしいプラグインです。

先日、deviseを使ったアプリケーションで「アカウントロック機能をつけれないか?」という要望を受け、ちょっとググッたのですが、具体的な例があんまり見つからなかったので、書いておきます。

ってか、ほとんどdeviseの機能を使っただけで、エントリにするほどのことでもないかもしれませんが、ま、私の備忘録も兼ねているので。

カラムの追加

Deviseのインストール時にUsersテーブルから作るのでしたら

  create_table :users do |t|
    t.database_authenticatable
    t.confirmable
    t.timestamps
  end

ってな感じで書けるのですが、すでにUsersテーブルは存在しているしなぁと思って、アカウントロックに必要なカラムだけadd_columnすればいいやと思い、色々調べてみました。

すると、「devise / lib / generators / active_record / devise_generator.rb」に「migration_data」ってメソッドがあって、そこに

      ## Lockable
      # t.integer  :failed_attempts, :default => 0 # Only if lock strategy is :failed_attempts
      # t.string   :unlock_token # Only if unlock strategy is :email or :both
      # t.datetime :locked_at

って行があったので、追加するカラムは「failed_attempts」「unlock_token」「locked_at」の3つを追加。

モデルの編集

Userモデルに対して、Deviseのlockableモジュールを結びつけるために、

  class User < ActiveRecord::Base
    devise :database_authenticatable, :confirmable, :recoverable, :rememberable, :trackable, :validatable, :lockable
  end

のように、「devise」と書かれた行の最後に「:lockable」を追加しました。

設定の変更

config\initializers\devise.rbを編集して、アカウントロックに関する機能の設定を行います。今回、アカウントロックの解除は手動で行うっていう事だったので、設定ファイルにある「config.unlock_strategy」を「:none」に。5回パスワード間違えたらアカウントロックするってことにしたので、「config.maximum_attempts」を「4」に(最大試行回数なので、5-1=4を設定する)。文頭にある「#」を外してコメントになっているのを解除しました。

config.unlock_strategy = :none
config.maximum_attempts = 4

これでおしまい

これで、アカウントロック機能が実装できたことになります。・・・あ、あっけない。

実際にログイン処理をやってみると、

  • パスワードを間違えると、「failed_attempts」に1加わる
  • 「config.maximum_attempts」の回数を「failed_attempts」が超えると「locked_at」に日付・時刻が入る
  • 「locked_at」に値が入っているとアカウントロックされていると判断されるみたい。ただ、これはロックの解除形式にも依存。
  • パスワードが合うと「failed_attempts」は0にもどる。これはアカウントロックされていても0になる。

という動きをしました。

また、ユーザがアカウントロックされているかを判定するには、「User#access_locked?」を、アカウントロックの解除を行うには「User#unlock_access!」を実行すれば良いみたい。「User#unlock_access!」は

  • failed_attemptsカラムを0にする
  • locked_atカラムをnilにする
  • バリデーションなしでsave

という処理を行うみたい。分かってみると単純な仕組み。

まとめ

実際、やってみると呆気無くできてしまって拍子抜け。ドキュメントを見つけることができなかったので、ソースから追っかけたんですが、以外と読めるもので、調べてみて楽しかった。