概要
Railsでhas_secure_password パスワードの変更時に、「現在のパスワードを入力する」っていうやつをどうやってやろうかなーと思って、考えたことをメモする
具体的には、現在のパスワードがとpassword_digestを称号して、一致するなら 真となる値(trueなど)を返す方法です。
Deviseの人
deviseならば valid_password?
を使ってください。
has_secure_passwordな人のやり方
class CreateUsers < ActiveRecord::Migration[6.1]
def change
create_table :users do |t|
t.text :password
end
end
end
class User > ApplicationRecord
has_secure_password
end
authenticateメソッドを使う
irb(main):001:0> user = User.new
(0.4ms) SELECT sqlite_version(*)
irb(main):002:0> user.password = 'hoge'
irb(main):003:0> user.password_digest
=> "$2a$12$kzeCnmviABPsc3hLDrLqWuXVFqp3Jweotl6jmWAOTv4YDhThEY/BW"
irb(main):004:0> user.authenticate_password('fuga')
=> false
irb(main):005:0> user.authenticate_password('hoge')
=> #<User id: nil, password_digest: [FILTERED]> # 一致した場合は自身を返す。 真となる。
BCrypt::Password#is_password?メソッドを使う
BCryptを直接叩いてもできます。参考にしたのhas_secure_passwordが定義されているモジュール内の下記のコードです。
irb(main):001:0> user = User.new
(0.4ms) SELECT sqlite_version(*)
irb(main):002:0> user.password = 'hoge'
irb(main):003:0> user.password_digest
=> "$2a$12$kzeCnmviABPsc3hLDrLqWuXVFqp3Jweotl6jmWAOTv4YDhThEY/BW" # この文字列を検証する
irb(main):009:0> password_digest = user.password_digest
irb(main):010:0> password_digest
=> "$2a$12$kzeCnmviABPsc3hLDrLqWuXVFqp3Jweotl6jmWAOTv4YDhThEY/BW"
irb(main):011:0> BCrypt::Password.new(password_digest).is_password?('fuga')
=> false # 一致しない
irb(main):012:0> BCrypt::Password.new(password_digest).is_password?('hoge')
=> true # 一致するので true
BCrypt::Password.new(password_digest).is_password?('hoge')
が肝です。 password_digestの暗号化された文字列が 検証したい文字列('hoge')から暗号化する文字列と一致するかを検証しています。
おまけ
Rails 6以降のhas_secure_passwordは password
というattributeもしくは password_digest
というカラム以外も使えます。 ( rails 5.2だと使えない 5.2のhas_secure_password )
たとえば、 recovery_password
という文字列を使う場合は、以下の通りです。
これは、便利だ。
class User > ApplicationRecord
has_secure_password :recovery_password, validations: false
end
所感
実は、パスワード管理 deviseしか使っていなかった。相談を機に調べたらとても勉強になった。
has_secure_passwordの中身を知ったらパスワードだけなら has_secure_passwordでいいかなーと思った。
devise・・・はまりどころが多いからできれば使いたくないーと思っていたので。