我正在尝试将现有的Admin模型转换为Devise。我们已经有了密码哈希,但显然不是Devise兼容的。我想要做的是接受登录表单并根据加密密码检查提供的密码。如果不正确,请使用旧哈希检查密码,如果匹配,请清空旧的password_hash字段并将Devise的密码设置为提供的密码并保存模型。
前进的最佳方式是什么?我怀疑我需要覆盖一些东西,可能是在自定义控制器中,但我不完全确定如何继续。
答案 0 :(得分:28)
您可以让Devise使用新的加密方案进行加密密码的“艰苦工作”,如https://gist.github.com/1704632所示:
class User < ActiveRecord::Base
alias :devise_valid_password? :valid_password?
def valid_password?(password)
begin
super(password)
rescue BCrypt::Errors::InvalidHash
return false unless Digest::SHA1.hexdigest(password) == encrypted_password
logger.info "User #{email} is using the old password hashing method, updating attribute."
self.password = password
true
end
end
end
答案 1 :(得分:3)
在Devise中使用bcrypt加密器,这就是我最终对遗留数据所做的事情:
在models / user.rb
中# Because we have some old legacy users in the database, we need to override Devises method for checking if a password is valid.
# We first ask Devise if the password is valid, and if it throws an InvalidHash exception, we know that we're dealing with a
# legacy user, so we check the password against the SHA1 algorithm that was used to hash the password in the old database.
alias :devise_valid_password? :valid_password?
def valid_password?(password)
begin
devise_valid_password?(password)
rescue BCrypt::Errors::InvalidHash
Digest::SHA1.hexdigest(password) == encrypted_password
end
end
正如您所看到的,设计在遇到无效哈希时会抛出InvalidHash异常,这在对旧版用户进行身份验证时会执行此操作。 我使用它来回退用于创建原始传统哈希的哈希算法。
虽然它不会更改密码,但如果需要,可以简单地将其添加到方法中。
答案 2 :(得分:3)
首先,您需要将password_salt和encrypted_password复制到新对象模型
使用这个因为我必须将我的数据库用户导出到另一个应用程序和旧的, 应用程序正在使用设计1.0.x和使用2.1.x的新应用程序
Class User < ActiveRecord::Base
alias :devise_valid_password? :valid_password?
def valid_password?(password)
begin
devise_valid_password?(password)
rescue BCrypt::Errors::InvalidHash
salt = password_salt
digest = nil
10.times { digest = ::Digest::SHA1.hexdigest('--' << [salt, digest, password, nil].flatten.join('--') << '--') }
digest
return false unless digest == encrypted_password
logger.info "User #{email} is using the old password hashing method, updating attribute."
self.password = password
self.password_salt = nil # With this you will knew what object already using the new authentication by devise
self.save
true
end
end
end
答案 3 :(得分:2)
如果您从SHA512迁移,解决方案比moeffju's SHA1 solution更复杂:
def valid_password?(password)
if has_legacy_password?
return false unless valid_legacy_password?(password)
convert_legacy_password!(password)
true
else
super(password)
end
end
protected
def has_legacy_password?
password_salt.present?
end
def convert_legacy_password!(password)
self.password = password
self.password_salt = nil
self.save
end
def valid_legacy_password?(password)
stretches = 10
salt = password_salt
pepper = nil
digest = pepper
stretches.times do
tokens = [salt, digest, password, pepper]
digest = Digest::SHA512.hexdigest('--' << tokens.flatten.join('--') << '--')
end
Devise.secure_compare(encrypted_password, digest)
end
请务必将stretches
和pepper
替换为用于加密密码的值。
答案 4 :(得分:-2)
按照Thomas Dippel的说明,我已经提出更新密码的要点: https://gist.github.com/1578362
# Because we have some old legacy users in the database, we need to override Devises method for checking if a password is valid.
# We first ask Devise if the password is valid, and if it throws an InvalidHash exception, we know that we're dealing with a
# legacy user, so we check the password against the SHA1 algorithm that was used to hash the password in the old database.
#SOURCES OF SOLUTION:
# http://stackoverflow.com/questions/6113375/converting-existing-password-hash-to-devise
# https://github.com/binarylogic/authlogic/blob/master/lib/authlogic/crypto_providers/sha512.rb
# https://github.com/plataformatec/devise/blob/master/lib/devise/encryptors/authlogic_sha512.rb
alias :devise_valid_password? :valid_password?
def valid_password?(password)
debugger
begin
devise_valid_password?(password)
rescue BCrypt::Errors::InvalidHash
stretches = 20
digest = [password, self.password_salt].flatten.join('')
stretches.times {digest = Digest::SHA512.hexdigest(digest)}
if digest == self.encrypted_password
#Here update old Authlogic SHA512 Password with new Devise ByCrypt password
# SOURCE: https://github.com/plataformatec/devise/blob/master/lib/devise/models/database_authenticatable.rb
# Digests the password using bcrypt.
# Default strategy for Devise is BCrypt
# def password_digest(password)
# ::BCrypt::Password.create("#{password}#{self.class.pepper}", :cost => self.class.stretches).to_s
# end
self.encrypted_password = self.password_digest(password)
self.save
return true
else
# If not BCryt password and not old Authlogic SHA512 password Dosn't my user
return false
end
end
end