我发现密码摘要在我的rails 4应用程序中无法正常工作 - 密码摘要以明文形式存储在数据库中。
user.rb
class User < ActiveRecord::Base
has_secure_password
validates :password_digest, length: { minimum: 6 }
end
我的用户数据库迁移文件如下:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :full_name
t.string :email
t.string :password_digest
t.timestamps null: false
end
end
end
任何想法我做错了什么?
修改 我在Gemfile中启用了bcrypt(我运行了bundle install)
gem 'bcrypt', '~> 3.1.7'
当我尝试在rails控制台中测试时,我收到一个无效的哈希错误:
2.2.1 :011 > user = User.new(full_name: 'abcd', email: 'abc@abc.com', password_digest: 'abcdef')
=> #<User id: nil, full_name: "abcd", email: "abc@abc.com", password_digest: "abcdef", created_at: nil, updated_at: nil>
2.2.1 :012 > User.find_by(full_name: 'david').try(:authenticate, 'abcdef')
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."full_name" = ? LIMIT 1 [["full_name", "david"]]
BCrypt::Errors::InvalidHash: invalid hash
from /usr/local/rvm/gems/ruby-2.2.1/gems/bcrypt-3.1.10/lib/bcrypt/password.rb:60:in `initialize'
from /usr/local/rvm/gems/ruby-2.2.1/gems/activemodel-4.2.4/lib/active_model/secure_password.rb:102:in `new'
from /usr/local/rvm/gems/ruby-2.2.1/gems/activemodel-4.2.4/lib/active_model/secure_password.rb:102:in `authenticate'
答案 0 :(得分:2)
这很奇怪,一切都应该有效。尝试使用rails控制台中的文档中的一些示例:
user = User.new(name: 'david', password: '', password_confirmation: 'nomatch')
user.save # => false, password required
user.password = 'mUc3m00RsqyRe'
user.save # => false, confirmation doesn't match
user.password_confirmation = 'mUc3m00RsqyRe'
user.save # => true
user.authenticate('notright') # => false
user.authenticate('mUc3m00RsqyRe') # => user
User.find_by(name: 'david').try(:authenticate, 'notright') # => false
User.find_by(name: 'david').try(:authenticate, 'mUc3m00RsqyRe') # => user
如果user.save
返回false
,您可能会查看user.errors
验证消息失败。
编辑:@madcow最终排序正确。现在,您需要将存储在password_digest
中的纯文本密码转换为bcrypt哈希值。
注意:您将无法使用此代码恢复纯文本密码!如果您需要纯文本密码,请务必事先备份您的表格。
为单个用户试用此代码,如果一切正常,请将此技术应用于其他用户:
user = User.find_by(name: 'david')
user.password = user.password_confirmation = user.password_digest
user.save!
我们从user.password
分配user.password_digest
您的纯文本密码。由于has_secure_password
重新定义了password=
方法,因此您的纯文本密码应该有效地存储回password_digest
列,但现在作为哈希。
更新所有用户:
User.find_each do |user|
user.password = user.password_confirmation = user.password_digest
user.save!
end
答案 1 :(得分:2)
您无意中直接在密码摘要字段中保存明文密码,至少在您的控制台示例中是这样。这就是为什么密码存储为明文而不是哈希。
而不是在控制台中输入:
user = User.new(full_name: 'abcd', email: 'abc@abc.com', password_digest: 'abcdef')
输入:
user = User.new(full_name: 'abcd', email: 'abc@abc.com', password: 'abcdef', password_confirmation: 'abcdef')
user.save
然后找到用户:
User.find_by(full_name: 'abcd').try(:authenticate, 'abcdef')
切勿直接设置:password_digest
。始终通过:password
和:password_confirmation
字段进行设置。
顺便说一句,你得到的是无效的哈希错误,因为它试图解密你的明文(不是有效的哈希):password_digest
值。