将现有密码哈希转换为Devise

我正在尝试将现有的Admin模型转换为Devise。 我们已经有了密码哈希,但显然不是Devise兼容的。 我想要做的是接受登录表单并根据加密密码检查提供的密码。 如果不正确,请使用旧哈希检查密码,如果匹配,请清空旧的password_hash字段并将Devise的密码设置为提供的密码并保存模型。

前进的最佳方式是什么? 我怀疑我需要覆盖一些东西,可能是在自定义控制器中,但我不完全确定如何继续。

您可以让Devise使用新的crypt方案进行加密密码的“艰苦工作”,如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 

在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 

正如您所看到的,设计在遇到无效哈希时会抛出InvalidHashexception,这在对旧版用户进行身份validation时会执行此操作。 我使用它来回退用于创建原始传统哈希的哈希算法。

它不会更改密码,但如果需要,可以简单地将其添加到方法中。

首先,您需要将password_salt和encrypted_pa​​ssword复制到新的对象模型

使用这个因为我必须将我的数据库用户导出到另一个应用程序和旧的应用程序使用设计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 

如果你从SHA512迁移,那么解决方案比moeffju的SHA1解决方案更复杂 :

 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 

务必使用用于加密密码的值替换stretchespepper

按照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