ruby-on-rails - Rails 4 - 仅当当前密码正确时才允许更改密码

标签 ruby-on-rails authentication model passwords bcrypt-ruby

在我的应用中,用户可以编辑他们的个人资料信息。在编辑配置文件表单上,用户可以更改所有字段(姓名、职务等)。在同一个表单上有三个字段:current_password , password , 和 password_confirmation .我正在使用 bcrypthas_secure_password密码认证功能。我根本不使用设计。

我希望用户只有在提供了正确的当前密码后才能更改他们的密码。我之前在 update 中使用以下代码完成了这项工作我的用户 Controller 的方法:

# Check if the user tried changing his/her password and CANNOT be authenticated with the entered current password
if !the_params[:password].blank? && !@user.authenticate(the_params[:current_password])
  # Add an error that states the user's current password is incorrect
  @user.errors.add(:base, "Current password is incorrect.")
else    
  # Try to update the user
  if @user.update_attributes(the_params)
    # Notify the user that his/her profile was updated
    flash.now[:success] = "Your changes have been saved"
  end
end

然而,这种方法的问题在于,如果当前密码不正确,它会丢弃对用户模型的所有更改。如果当前密码不正确,我想保存对用户模型的所有更改,但不保存密码更改。我试过像这样拆分 IF 语句:
# Check if the user tried changing his/her password and CANNOT be authenticated with the entered current password
if !the_params[:password].blank? && !@user.authenticate(the_params[:current_password])
  # Add an error that states the user's current password is incorrect
  @user.errors.add(:base, "Current password is incorrect.")
end

# Try to update the user
if @user.update_attributes(the_params)
  # Notify the user that his/her profile was updated
  flash.now[:success] = "Your changes have been saved"
end

这不起作用,因为即使当前密码不正确,用户也可以更改他/她的密码。单步执行代码时,尽管“当前密码不正确”。错误已添加到 @user ,经过 update_attributes方法,它似乎忽略了这个错误信息。

顺便说一句,current_password字段是我的用户模型中的虚拟属性:
attr_accessor :current_password

我一直在努力解决这个问题几个小时,所以我真的可以使用一些帮助。

谢谢!

解决方案

感谢 papirtiger ,我得到了这个工作。我从他的回答中稍微更改了代码。下面是我的代码。请注意,任一代码片段都可以正常工作。

在用户模型 (user.rb)
class User < ActiveRecord::Base
  has_secure_password

  attr_accessor :current_password

  # Validate current password when the user is updated
  validate :current_password_is_correct, on: :update

  # Check if the inputted current password is correct when the user tries to update his/her password
  def current_password_is_correct
    # Check if the user tried changing his/her password
    if !password.blank?
      # Get a reference to the user since the "authenticate" method always returns false when calling on itself (for some reason)
      user = User.find_by_id(id)

      # Check if the user CANNOT be authenticated with the entered current password
      if (user.authenticate(current_password) == false)
        # Add an error stating that the current password is incorrect
        errors.add(:current_password, "is incorrect.")
      end
    end
  end
end

我的用户 Controller 中的代码现在很简单:
# Try to update the user
if @user.update_attributes(the_params)
  # Notify the user that his/her profile was updated
  flash.now[:success] = "Your changes have been saved"
end

最佳答案

您可以在模型级别添加自定义验证,以检查密码是否已更改:

class User < ActiveRecord::Base
  has_secure_password

  validate :current_password_is_correct,
           if: :validate_password?, on: :update

  def current_password_is_correct
    # For some stupid reason authenticate always returns false when called on self
    if User.find(id).authenticate(current_password) == false
      errors.add(:current_password, "is incorrect.")
    end
  end

  def validate_password?
    !password.blank?
  end

  attr_accessor :current_password
end

关于ruby-on-rails - Rails 4 - 仅当当前密码正确时才允许更改密码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30293379/

相关文章:

javascript - Ruby on Rails - 更改页面滚动上的 Logo 图像未激活

css - Rails : For every x items, 放了一个新的 html 标签

ruby-on-rails - 铁路时间 :Minutes Dropdowns

asp.net-mvc - ASP.NET MVC 登录 ReturnUrl 始终为 NULL?

c# - 访问 javascript 文件中的模型属性?

ruby-on-rails - 如何在 Fabrication 的计数参数中使用 transient 属性?

authentication - 如何在tinyproxy中配置用户名和密码?

java - 如何在tomcat中跳过http基本身份验证?

ruby-on-rails - 同名类

ruby-on-rails - 如何在 Rails 中为不同的用户建模