【问题标题】:Validating against blank password in Rails在 Rails 中验证空白密码
【发布时间】:2019-08-13 13:31:43
【问题描述】:

我为我的User 模型添加了密码密码验证:

validates :password, presence: true
validates :password, confirmation: { case_sensitive: true }

但是当我想更新users 上的其他字段时,这些验证导致交易无效,因为password 不存在。

通过一些研究,我意识到如果password 不存在,我可以跳过这些验证:

validates :password, presence: true, if: :validate_password?
validates :password, confirmation: { case_sensitive: true }, if: :validate_password?


def validate_password?
  password.present? || password_confirmation.present?
end

但是,现在当我提交空白密码和密码确认时,validate_password? 返回false。我真的不明白发生了什么,因为

@user.update_attributes(password_reset_edit_params) 返回true

在哪里

password_reset_edit_params<ActionController::Parameters {"password"=>"", "password_confirmation"=>""} permitted: true>

但在里面

def validate_password?
  password.present? || password_confirmation.present?
end

passwordpassword_confirmation 评估为 nil,而我的 @user 密码不会更新为空字符串。

我应该提到我正在使用 Bcrypt,@user.password 实际上总是会评估为nil,而password_digest 是可用的。

那么解决方法是什么?最终我想我的问题很简单:

当我不尝试提交密码时如何忽略密码验证,但在提交空字符串时也允许这些验证?

我突然想到,我可以在控制器中添加一个不允许传递空字符串的条件,但必须有一个巧妙的方法来解决这个问题。

非常感谢任何帮助。谢谢!

【问题讨论】:

  • 从您的验证中删除 , if: :validate_password?
  • 但这让我回到了我的第一个问题,其中每当我尝试更新User 的实例(有或没有password)时,都会触发验证,如果我尝试在不包含密码的情况下更新用户,验证会返回错误。

标签: ruby-on-rails ruby validation activerecord bcrypt


【解决方案1】:

最终我只是在用户模型上验证密码格式和确认:

validates :password,  confirmation: true,
                      length: {within: 6..40},
                      allow_blank: true

并根据控制器中的空白密码/password_confirmation 对输入数据进行清理。

if password_reset_edit_params[:password].blank? || password_reset_edit_params[:password_confirmation].blank?
      @user.errors[:password] << "can't be blank" if password_reset_edit_params[:password].blank?
      @user.errors[:password_confirmation] << "can't be blank" if password_reset_edit_params[:password_confirmation].blank?
      render 'edit'

【讨论】:

    【解决方案2】:

    如果你使用 Bcrypt 和摘要,你可以在你的模型中使用例如

    has_secure_password
    validates :password, length: { minimum: 8 }, allow_blank: true
    

    在这种情况下,验证仅适用于设置和更改密码。

    如果您不更改密码,则无需输入密码。

    另一种方式

    validates :password, presence: true, on: :create
    

    【讨论】:

    • 我遇到的困难是:如果我包含allow_blank: true,然后像@user.update_attributes(password: '', password_confirmation: '')一样提交空白密码,则不会返回错误。如何在不包含密码的情况下返回 can't be blank 错误,同时允许更新?
    • allow_blank 确实解决了我的大部分问题。如果将空字符串作为密码提交,我只需在控制器上添加错误。谢谢。
    • 在下面查看我的回答,了解我的意思。
    • 为什么需要它?参数验证和胖控制器不是 Rails 方式
    • 这是我能想到的唯一方法来阻止用户输入password: ''password_confirmation: ''。这是我无法以任何其他方式解决的一个极端情况。
    【解决方案3】:

    在 Rails 中,您不是在验证参数,而是在验证模型。

    不要“如果密码不存在则跳过验证”。这就是验证的目的。验证旨在验证 model,而不是参数。如果模型的密码为空,并且需要密码存在,则该模型是无效模型。总是。

    但是当我想更新用户的其他字段时,这些验证导致交易无效,因为密码不存在。

    这不是因为密码不存在,而是因为 User 的实例中没有密码。它应该工作的方式是:

    1. 使用密码创建用户并验证:User.create(name: "Me", password: "something that isn't nil")
    2. 用户更新:User.update(name: "New name") # password is inside the model still so it is still valid

    这就是它的工作原理。如果您希望用户能够拥有 nil / 空密码,那么您不应该尝试在模型中放置存在验证。

    【讨论】:

    • 我的经历与你的解释相矛盾。当我删除 validate_password? 并尝试执行以下操作时:@user.update_attributes(first_name: 'jimmy') 记录不保存,@user.errors.full_messages 评估为 ["Password can't be blank"]
    • @user 有密码吗?显示p @user.password的输出
    • 它是nil(正如我在最初的帖子中解释的那样),但用户有一个password_digest@user.authenticate('password') 返回所需的结果。
    • 您需要删除您的意大利面条式验证并从最简单的validates_presence_of :password 开始。如果密码必须存在,那么这是正确的验证。句号。如果您的@user 没有密码,则它们不能存在。就那么简单。其他任何事情,就您的新问题开始一个新线程。你刚刚在 cmets 所做的就是证明我的观点。您尝试更新没有密码且验证失败的 @user 的属性。完美的。我们想要那个。现在给@user 一个:password 并保存它们。然后尝试更新它们。这就是重点。
    • 但是 bcrypt 不会在 User 模型上存储密码。它接受密码和可选的密码确认,并创建一个称为密​​码摘要的散列密码。该模型包括 bcrpyt 方法has_secure_password,其中包括在创建用户时的验证,但它不涉及更新用户。 api.rubyonrails.org/classes/ActiveModel/SecurePassword/… 那么这只是 bcrypt 的一个固有问题吗?如果我想更新用户的密码,我必须提交密码和密码确认,但这两个字段在db中没有持久化。
    猜你喜欢
    • 2011-01-11
    • 2014-04-15
    • 2014-08-16
    • 1970-01-01
    • 2011-07-04
    • 1970-01-01
    • 2012-02-25
    • 2015-02-02
    • 1970-01-01
    相关资源
    最近更新 更多