deviseのアカウントロック解除メールを自動送信から手動送信に変える

はじめに

認証機能を提供する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()メソッドを実行してあげて下さい。

以上です。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA