首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么在添加密码恢复后密码验证不起作用?

为什么在添加密码恢复后密码验证不起作用?
EN

Stack Overflow用户
提问于 2019-12-11 22:28:30
回答 2查看 124关注 0票数 0

面对一个我不太清楚的问题。我在注册过程中使用了密码验证。

代码语言:javascript
复制
def pass_val
    if password_digest.count("a-z") <= 0 || password_digest.count("A-Z") <= 0 
      errors.add(:password, "must contain 1 small letter, 1 capital letter and minimum 8 symbols")
    end
  end
validates :password_digest, presence: true,
                            length: { minimum: 8 }

我使恢复用户密码成为可能,并且验证刚刚停止工作。我将验证中的所有password_digest更改为password,并且验证再次工作。但是,在那之后,密码恢复消失了,这开始诅咒验证。

代码语言:javascript
复制
NoMethodError in PasswordResetsController#create
undefined method `count' for nil:NilClass

如果我再次将所有password更改为password_digest,验证将消失,但恢复密码将再次工作。

更新

  1. 在控制台中使用password -验证有效(它也可以在站点上工作)。密码恢复无效)。
  2. 在控制台中使用password_digest -验证也有效(它在站点上不起作用,恢复密码有效)。

UPDATE 2 此外,当一封信被发送到邮件时(在发送之前),在密码恢复过程中发生错误,而不是在密码更改期间发生错误。

更新3 PasswordResetsController中的创建方法:

代码语言:javascript
复制
def create
  author = Author.find_by_email(params[:email])
  author.send_password_reset if author
  flash[:success] = "Email sent with password reset instructions."
  redirect_to root_path
end

更新4发送password_reset:

代码语言:javascript
复制
  def send_password_reset
    confirmation_token
    self.password_reset_sent_at = Time.zone.now
    save!
    AuthorMailer.password_reset(self).deliver!
  end

但这封信没有寄出,崩溃到了这个地步。--我要强调的是,我要么在验证中使用,要么在验证中使用password_digest,并且密码恢复工作。或者我在验证和验证工作中使用password,但是密码恢复没有。

另外,值得注意的是,PasswordResetsController中的create方法并不用于更改密码,而是用于向电子邮件发送电子邮件。我不明白为什么验证会对他发誓。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-12-12 18:57:40

错误出现在send_password_reset方法中。将(: validate => false)添加到此方法中,它起了作用。

代码语言:javascript
复制
  def send_password_reset
    confirmation_token
    self.password_reset_sent_at = Time.zone.now
    save!(:validate => false)
    AuthorMailer.password_reset(self).deliver!
  end

在评估中,我使用password

票数 0
EN

Stack Overflow用户

发布于 2020-07-21 16:28:10

看来你自己已经找到解决办法了。但是,我不确定您是否理解为什么会发生这种情况。

让我们从一个重要的事实开始,password_digest不包含密码,而是包含密码的散列版本。(散列函数的结果也称为摘要。)您需要将验证添加到password属性,因为它包含实际的密码。

当您将新密码分配给作者时,将为密码和密码摘要分配一个新值。您可以想象password设置器看起来如下所示:

代码语言:javascript
复制
def password=(password)
  @password = password
  @password_digest = do_some_hash_magic(password)
end

因为password是在分配给作者时设置的,所以您可以验证它的内容。

另一件需要知道的重要事情是,实际的密码从未保存到数据库中,只有密码摘要(出于安全原因)。因此,当您(重新)从数据库加载实例时,password设置为nil,因为应用程序不再知道它是什么。

与其使用save(validate: false)跳过验证,我建议使用:allow_nil选项或使验证条件只在password不是nil时触发验证。

代码语言:javascript
复制
validates :password, length: { in: 8..255 }, allow_nil: true

validates :password, format: { with: /\p{Lower}/,    message: :no_lower   }, allow_nil: true
validates :password, format: { with: /\p{Upper}/,    message: :no_upper   }, allow_nil: true
validates :password, format: { with: /\p{Digit}/,    message: :no_digit   }, allow_nil: true
validates :password, format: { with: /[\p{S}\p{P}]/, message: :no_special }, allow_nil: true

或者,您可以更显式地使用带有自定义上下文的:on选项,只在您希望它们触发验证时触发它们:

代码语言:javascript
复制
validates :password, length: { in: 8..255 }, on: :password

validates :password, format: { with: /\p{Lower}/,    message: :no_lower   }, on: :password
validates :password, format: { with: /\p{Upper}/,    message: :no_upper   }, on: :password
validates :password, format: { with: /\p{Digit}/,    message: :no_digit   }, on: :password
validates :password, format: { with: /[\p{S}\p{P}]/, message: :no_special }, on: :password

上下文不必以属性命名,使用:foo而不是:password也可以。然后,您可以通过调用valid?save时传递上下文来运行这些验证。

代码语言:javascript
复制
author.valid?(:password)
author.save(context: :password)

如果使用Rails 5或更高版本,如果要运行多种验证组合,则可以将多个上下文作为数组传递。author.valid?([:create, :password])

有关使用的regexes的更多信息,请查看regexp文档

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59295083

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档