実現したいこと
Railsでdevise gemを使っている環境にて、暗号化前のパスワードが暗号化後のパスワードと一致しているか確認したい。
例えば、以下のようなケースです。
- 「このパスワードで設定したはずだがログインできず、パスワードがちゃんと設定されてるか確認してほしい」という問い合わせに対して調査する場合
- 有効期限を持たせた複数のパスワードを、過去履歴を含めてDBに保持しており、古いパスワードが入力された場合に「それは古いパスワードです」とアラートを出したい場合
deviseでは、パスワードは暗号化されDBに保存されているため、DBのレコードを参照するだけだと、元のパスワードがどんなものだったかわかりません。
解決方法
「入力されたパスワードを自力で暗号化したものでDBを検索する」という方法もありますが、そこまでしなくても一発でわかるvalid_password?
メソッドがdeviseで用意されています。
レシーバにはActiveRecordインスタンス(パスワードが保存されたレコード)、引数に暗号化前のパスワードを指定します。
基本例
# ユーザが入力した"hogehoge"というパスワードが、id=1234のユーザのパスワードと一致するか確認したい場合
User.find(1234).valid_password?("hogehoge")
# => 戻り値はboolean
# paramsで渡ってきたpassword(暗号化前)が、id=1234のユーザに設定されたパスワードと一致するか確認したい場合
User.find(1234).valid_password?(params[:password])
応用例
ちょっと発展させた例です。
例えば、有効期限を持たせた複数のパスワードを、過去履歴を含めてUserPassword
モデルに保持しており、
古いパスワードが入力された場合に「それは古いパスワードです」とアラートを出したい場合
def old_password?(input_password)
old_passwords = UserPassword.find(1234).where.not(expired_at: nil)
old_passwords.any? {|old_pw| old_pw.valid_password?(input_password) }
end
redirect_to new_session_path, alert: "入力されたパスワードは有効期限が切れています" if old_password?(params[:password])
参考サイト
devise gemでは以下で定義されているようです。