0

我在用户模型中使用 has_secure_password 。我已经实现了一种让用户在模型之外更改密码的方法,但是为了保持干燥,我正在尝试将所需的验证从控制器移动到模型。

用户模型看起来像这样:

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

  has_secure_password

  field: :password_digest, type: String

  attr_accessible :password, :password_confirmation, :current_password
end

用户通过提交以下内容更改密码:

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

我在当前用户的用户模型上使用 update_attributes(params[:user]) 。我的问题是在使用验证之前调用 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

authenticate 是基于从 user[password] 生成的新 password_digest 进行身份验证。是否有一种优雅的方式来访问旧的 password_digest 值以进行身份​​验证?我的一个想法是重新查询用户以获得对另一种身份验证方法的访问权限,该方法将根据旧的 password_digest 值进行身份验证。问题是它不是一个干净的解决方案。

4

2 回答 2

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
于 2013-01-28T08:37:11.933 回答
0

password_digest 字段有与之关联的 ActiveModel::Dirty 方法,所以我决定使用:

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=如果使用其他功能,将来可能会引入错误password=

于 2012-09-30T18:44:00.907 回答