53

我正在努力完成一个项目。我正在使用用户模型。当我注册时,一切似乎都很好。但是当我尝试登录同一个成员时,我得到了这个错误。

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

BCrypt::Errors::InvalidHash (invalid hash):
  app/controllers/sessions_controller.rb:8:in `create'

我的*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

用户模型是:

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 

这是我的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

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

4

3 回答 3

91

这意味着存储的哈希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

然后,您可以根据您有权访问的 sha1 密码哈希创建 bcrypt password_digests 。

您将像这样进行身份验证:

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

我在上面的示例中使用了 SHA1,但这也适用于其他散列算法。

于 2012-06-14T17:37:30.667 回答
14

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

于 2021-01-07T06:52:28.203 回答
13

我已经有了实时用户,并且同样已经将未加密的密码保存到了数据库中。一旦我开始使用 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 

希望这可以帮助。

于 2014-11-06T15:30:47.973 回答