はじめに
認証機能を提供するGEMでおなじみのdeviseですが、試行回数の制限を設定を行えることをご存知でしたでしょうか。
まずアカウントロック用のカラムを追加します。下記の様なマイグレーションファイルを作成してから、rails db:migrate
を実行して下さい。
class AddLockableColumnsToUsers < ActiveRecord::Migration[6.0]
def change
add_column :users, :failed_attempts, :integer, :default => 0
add_column :users, :unlock_token, :string
add_column :users, :locked_at, :datetime
add_index :users, :unlock_token, :unique => true
end
end
次にモデルクラスのdevise :lockable
を有効にします。
そしてconfig/initializers/devise.rb
のアカウントロックに関わる部分のコメントアウトを削除して次のように設定することで、試行回数によってアカウントロックを行うことが可能です。
# ==> Configuration for :lockable
# Defines which strategy will be used to lock an account.
# :failed_attempts = Locks an account after a number of failed attempts to sign in.
# :none = No lock strategy. You should handle locking by yourself.
config.lock_strategy = :failed_attempts
# Defines which key will be used when locking and unlocking an account
config.unlock_keys = [:email]
# Defines which strategy will be used to unlock an account.
# :email = Sends an unlock link to the user email
# :time = Re-enables login after a certain amount of time (see :unlock_in below)
# :both = Enables both strategies
# :none = No unlock strategy. You should handle unlocking by yourself.
config.unlock_strategy = :both
# Number of authentication tries before locking an account if lock_strategy
# is failed attempts.
config.maximum_attempts = 6
# Time interval to unlock the account if :time is enabled as unlock_strategy.
config.unlock_in = 1.hour
# Warn on the last attempt before the account is locked.
config.last_attempt_warning = true
上記は次の様な設定内容になります。
- アンロックにメールを使用
- アンロック時間を使用(1h)
- 試行回数が6回を超えたらアカウントをアンロック
- 試行回数が6回目の時に警告文を返す
これがdeviseのアカウントロック設定の概要です。この設定だとアカウントがアンロック状態になったタイミングでメールを自動送信します。この挙動を変える方法を今回はまとめてみました。
アンロックメールの自動送信を無効にする
devise GEMのソースコードを読んでみると、models/locable.rb
に下記のコードが書かれていました。
# Lock a user setting its locked_at to actual time.
# * +opts+: Hash options if you don't want to send email
# when you lock access, you could pass the next hash
# `{ send_instructions: false } as option`.
def lock_access!(opts = { })
self.locked_at = Time.now.utc
if unlock_strategy_enabled?(:email) && opts.fetch(:send_instructions, true)
send_unlock_instructions
else
save(validate: false)
end
end
コメントにもある通りlock_access!()
メソッドの引数に{ send_instructions: false }
を渡してあげれば、アンロック時の自動送信を無効化出来ます。
これをどうやって設定するかというと、lock_access!()
メソッドをオーバーライドしてあげるだけで大丈夫です。deviseを正しくマウントしているなら、lock_access!()
メソッドを呼び出すのはアカウントに当たるモデルですから、そのモデルにコピペしてあげるだけです。
下記の例のように記述してみて下さい。
※一部抜粋
class User < ApplicationRecord
devise :lockable
def lock_access!(opts = { send_instructions: false })
self.locked_at = Time.now.utc
if unlock_strategy_enabled?(:email) && opts.fetch(:send_instructions, true)
send_unlock_instructions
else
save(validate: false)
end
end
end
これで設定は完了です。アカウンがロックされてもメールは送信されなくなったはずです。
手動でメールを送信する処理については、それ用のコントローラーを作成して該当のアクション内で、send_unlock_instructions()
メソッドを実行してあげて下さい。
以上です。