Как переопределить метод ActiveModel :: SecurePassword.authenticate? - PullRequest
0 голосов
/ 22 января 2020

Я пытаюсь переопределить метод authenticate в этом файле: https://github.com/rails/rails/blob/f33d52c95217212cbacc8d5e44b5a8e3cdc6f5b3/activemodel/lib/active_model/secure_password.rb#L61

Я должен убедиться, что если пользователь без password_digest попытается пройти аутентификацию, метод возвращает false вместо повышения BCrypt::Errors::InvalidHash

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

Я пробовал это:

# config/initializers/secure_password.rb

module ActiveModel
  module SecurePassword
    class InstanceMethodsOnActivation
      def authenticate(unencrypted_password)
        begin
          BCrypt::Password.new(password_digest).is_password?(unencrypted_password) && self
        rescue BCrypt::Errors::InvalidHash => e
          false
        end
      end
    end
  end
end

Это мой тест:

it 'should authenticate with false response if no digest (legacy password system)' do
  user.activate!
  user.update(password_digest: nil)
  expect(user.authenticate('test')).to be false
end

И сообщение об ошибке:

BCrypt::Errors::InvalidHash: invalid hash

  0) User should authenticate with false response if no digest (legacy password system)
     Failure/Error: expect(user.authenticate('test')).to be false

     BCrypt::Errors::InvalidHash:
       invalid hash

Я обновляю наше приложение до Rails 6, и SecurePassword был переписан, я не могу изменить метод снова. Я думаю, проблема в том, что метод authenticate теперь определен в методе инициализации InstanceMethodsOnActivation. Я нахожу это странным ... И я не знаю, как это изменить.

Пожалуйста, кто-нибудь может мне помочь?

1 Ответ

1 голос
/ 22 января 2020

Я думаю, вам не нужно вносить исправления в реализацию gem, потому что я думаю, что в вашем случае супер-трюка было бы достаточно:

class User < ApplicationRecord
  def authenticate(*args)
    if password_digest.nil? # or `.blank?` (if you have '' as default instead of nil)
      false
    else
      # else, proceed normally
      super(*args)
      # `super` alone also works, as it automatically pass in all arguments
    end
  end
end

Пример использования:

user = User.new
user.password_digest = nil

puts user.authenticate('somepassword')
# => false

Относительно вашей проблемы "проблем":

  • Это должно выглядеть следующим образом:
# app/models/concerns/your_own_named_concern.rb

module YourOwnNamedConcern
  extend ActiveSupport::Concern

  included do
    def authenticate(*args)
      if password_digest.nil?
        false
      else
        super(*args)
      end
    end
  end
end

# app/models/user.rb
class User < ApplicationRecord
  include YourOwnNamedConcern

  has_secure_password
end

# app/models/admin.rb
class Admin < ApplicationRecord
  include YourOwnNamedConcern
end

Пример использования:

user = User.new
user.password_digest = nil

puts user.authenticate('somepassword')
# => false

admin = Admin.new
admin.password_digest = nil

puts admin.authenticate('somepassword')
# => false
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...