尝试登录时出现"BCrypt :: Errors :: InvalidHash"

yts*_*jam 45 ruby-on-rails heroku bcrypt

我正在努力完成一个项目.我正在使用用户模型.当我注册一切似乎没问题.但是当我尝试签署同一个成员时,我收到了这个错误.

我们很抱歉,但有些不对劲. heroku日志文件显示错误为:

BCrypt::Errors::InvalidHash (invalid hash):
  app/controllers/sessions_controller.rb:8:in `create'
Run Code Online (Sandbox Code Playgroud)

my *sessions_controller*是:

class SessionsController < ApplicationController

  def new
  end

   def create
    user = User.find_by_email(params[:session][:email])
    if user && user.authenticate(params[:session][:password])
      sign_in user
      redirect_to user
    else
      flash.now[:error] = 'Invalid email/password combination'
      render 'new'
    end
  end


  def destroy
    sign_out
    redirect_to root_path
  end
end
Run Code Online (Sandbox Code Playgroud)

用户模型是:

class User < ActiveRecord::Base
  attr_accessible :email, :name, :nickname,:password, :password_confirmation 
  has_secure_password


  before_save { |user| user.email = email.downcase }
  before_save { |user| user.nickname = nickname.downcase }
  before_save :create_remember_token
....validations......

    private

    def create_remember_token
      self.remember_token = SecureRandom.urlsafe_base64
    end
end 
Run Code Online (Sandbox Code Playgroud)

这是我的session.helper

module SessionsHelper

  def sign_in(user)
    cookies.permanent[:remember_token] = user.remember_token
    self.current_user = user
  end
  def signed_in?
    !current_user.nil?
  end

  def current_user=(user)
    @current_user = user
  end

  def current_user
    @current_user ||= User.find_by_remember_token(cookies[:remember_token])
  end

  def sign_out
    self.current_user = nil
    cookies.delete(:remember_token)
  end
end
Run Code Online (Sandbox Code Playgroud)

我试过heroku rake db:migrate,heroku restart ..没有变化.

Ben*_*Lee 80

这意味着存储的哈希password_digest不是有效的BCrypt哈希(包括该字段为空).

根据评论,看起来你刚刚创建了用户has_secure_password,因此密码摘要从未被存储过.查看数据库,您可能会看到password_digest该用户为空.从数据库中删除用户并使用新的工作代码重新创建它,它应该工作.

虽然在评论中讨论时,我做了一个(不正确的)猜测密码错误的原因,我已经写了解释.所以这里是任何未来的访问者都有这个问题,即使它不直接在这里应用:


当您从使用SHA1或其他算法切换到BCrypt但无法在BCrypt中重新散列密码时,通常会发生这种情况.既然你没有访问原始密码(或者至少你不应该...),这是一个有点难看切换,因为你必须使用两个 BCrypt和原来的认证方案.例如,如果您以前使用过SHA1并且现在使用BCrypt,则必须将SHA1密码哈希视为 BCrypt输入的纯文本密码.例如,您可以创建一个BCrypt摘要,如下所示:

sha1_password = Digest::SHA1.hexdigest("#{salt}#{real_password}")
self.password_digest = BCrypt::Password.create(sha1_password).to_s
Run Code Online (Sandbox Code Playgroud)

然后,您可以创建基于您的SHA1哈希密码bcrypt password_digests 访问.

你会这样验证:

sha1_password = Digest::SHA1.hexdigest("#{salt}#{attempted_password}")
BCrypt::Password.new(self.password_digest) == sha1_password
Run Code Online (Sandbox Code Playgroud)

我在上面的示例中使用了SHA1,但这也适用于其他哈希算法.


nfr*_*d21 12

我已经有了实时用户,同样已经将未加密的密码保存到数据库中.一旦我开始使用bcrypt,它就会期待一个加密的密码,当它没有找到它时,就会产生这个错误.

因此,我添加了此救援以捕获错误并提示旧用户重置其密码:

begin
    # your code that attempts to login the user
rescue BCrypt::Errors::InvalidHash
  flash[:error] = 'We recently adjusted the way our passwords are stored. Please click the "forgot username or password?" link to re-establish your password. Thank you for your understanding!'
  redirect_to password_resets_url
end 
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助.

  • 我认为依赖 authentication() 引发未记录的异常不是一个好主意;通过检查 password_digest.empty 来解决它更干净吗?在调用 authentication() 之前。 (3认同)

小智 8

BCrypt gem 的更新为我解决了这个问题

  • 就我而言,我从 bcrypt 3.1.11 升级到 3.1.16,它解决了该错误。https://github.com/heartcombo/devise/issues/4861 似乎相关。我以前的密码不起作用,我必须重置它。 (2认同)
  • 同样,从 3.1.11 升级到 3.1.16 为我解决了这个问题。 (2认同)