0

我在用戶模型中使用has_secure_password。我已經實現了一種讓用戶在模型之外更改密碼的方法,但爲了保持乾爽,我試圖將所需的驗證從控制器移至模型。has_secure_password驗證密碼更新驗證

用戶模型看起來是這樣的:對用戶:

user[current_password] - Currently stored password 
user[password] - New password 
user[password_confirmation] - New password confirmation 

我使用update_attributes方法(PARAMS [:用戶])

class User 
    include Mongoid::Document 
    include ActiveModel::SecurePassword 

    has_secure_password 

    field: :password_digest, type: String 

    attr_accessible :password, :password_confirmation, :current_password 
end 

用戶通過提交以下更改他們的密碼模型爲當前用戶。我的問題是,調用更新的update_attributes使用驗證之前password_digest,所以下面的代碼將無法正常工作:

def password_validation_required? 
    password_digest.blank? || !password.blank? || !password_confirmation.blank? 
end 

validate(on: :update, if: :password_validation_required?) do 
    unless authenticate(current_password) 
    add(:current_password, 'invalid password') 
    end 
end 

身份驗證是基於用戶[密碼]中產生的新password_digest認證。有沒有一種優雅的方式來訪問舊的password_digest值進行身份驗證?我有一個想法是重新查詢用戶訪問另一個驗證方法,該方法將根據舊的password_digest值進行驗證。問題是這不是一個乾淨的解決方案。

+0

我會重新定義'密碼='http://api.rubyonrails.org/classes/ActiveModel/SecurePassword/InstanceMethodsOnActivation.html – apneadiving

+0

的重新定義'password ='的問題是我不得不在內部添加很多邏輯,這將防止未來的功能在某些管理功能中需要使用'password ='(例如'user.password = ...' ) – Parazuce

+0

我只能在'before_save'中移動摘要創建,或者...查看答案 – apneadiving

回答

0

的password_digest場加載ActiveModel具有::與之相關的骯髒的方法,所以我決定去:

validate(on: :update, if: :password_validation_required?) do 
    unless BCrypt::Password.new(password_digest_was) == current_password 
    errors.add(:current_password, "is incorrect") 
    end 
end 

這避免了需要重寫password=額外的邏輯可能在未來如果其他引入bug使用的功能password=

1

我覺得這一個比@ Parazuce的清潔了一下:

validate :validates_current_password 

    private 

    def validates_current_password 
    return if password_digest_was.nil? || !password_digest_changed? 
    unless BCrypt::Password.new(password_digest_was) == current_password 
     errors.add(:current_password, "is incorrect") 
    end 
    end