Преобразование существующего хеша пароля для разработки

Я пытаюсь преобразовать существующую модель администратора в Devise. У нас уже есть хеш-пароль, но он явно не совместим с Devise. Я хотел бы принять форму входа и проверить предоставленный пароль на зашифрованный пароль. Если это неверно, используйте старый хеш, чтобы проверить пароль, и если он соответствует, запустите старое поле password_hash и установите пароль разработчика на предоставленный пароль и сохраните модель.

Какой лучший способ двигаться вперед? Я подозреваю, что мне нужно что-то переопределить, возможно, в пользовательском контроллере, но я не совсем уверен, как действовать дальше.

Ответы

Ответ 1

Вы можете позволить 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

Ответ 2

Используя шифр bcrypt в Devise, это то, что я закончил с моими устаревшими данными:

В моделях /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

Как вы можете видеть, devise выдает исключение InvalidHash, когда он встречает недопустимый хеш, который он будет делать при аутентификации устаревшего пользователя. Я использую это, чтобы вернуться к алгоритму хеширования, используемому для создания исходного хэш файла.

Он не изменяет пароль, но может быть просто добавлен в метод, если это необходимо.

Ответ 3

Сначала вам нужно скопировать пароль_salt и encrypted_password в вашу новую объектную модель.

Используя это, потому что я должен экспортировать мою базу данных Пользователь в другое приложение и старый,  приложение использует devise 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

Ответ 4

Если вы переходите от 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

Обязательно замените stretches и pepper значениями, которые вы использовали для шифрования паролей.

Ответ 5

Следуйте инструкциям 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/info/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