【问题标题】:Lockable is not working in Devise可锁定在设计中不起作用
【发布时间】:2014-06-02 14:17:22
【问题描述】:

我已经在两个用户帐户 Admin 和 Customer 上实施了设计。注册登录功能工作正常。我正在尝试在管理员帐户上实现可锁定。我正在使用设计 3.2.4。

在特定时间输入错误凭据后,该帐户仍处于活动状态,并且不会记录 failed_attempts。

我已遵循此指南HERE

我的设计.rb:

Devise.setup do |config|
  config.secret_key = 'XXXXX_the_secret_key_XXXXXXX'

  config.mailer_sender = 'mymail@domain.com'

  require 'devise/orm/active_record'

  # config.authentication_keys = [ :email ]

  # config.request_keys = []

  config.case_insensitive_keys = [ :email ]

  config.strip_whitespace_keys = [ :email ]

  # config.params_authenticatable = true

  # config.http_authenticatable = false

  # config.http_authenticatable_on_xhr = true

  # config.http_authentication_realm = 'Application'

  # config.paranoid = true

  # passing :skip => :sessions to `devise_for` in your config/routes.rb
  config.skip_session_storage = [:http_auth]

  # config.clean_up_csrf_token_on_authentication = true

  config.stretches = Rails.env.test? ? 1 : 10

  # config.pepper = '38635688e9d775b28e8da07b695dfced7b3bd4899c0a9a2a0f9b5ed5a8113e79864f76039166f827ef0134452fc0080f279adc4d1724362e079d0af3361edaf5'

  # config.allow_unconfirmed_access_for = 2.days

  # config.confirm_within = 3.days

  config.reconfirmable = true

  # config.confirmation_keys = [ :email ]

  # config.remember_for = 2.weeks

  # config.extend_remember_period = false

  # config.rememberable_options = {}

  # Range for password length.
  config.password_length = 8..128

  # config.email_regexp = /\A[^@]+@[^@]+\z/

  # config.timeout_in = 30.minutes

  # config.expire_auth_token_on_timeout = false

  # :failed_attempts = Locks an account after a number of failed attempts to sign in.
  # :none            = No lock strategy. You should handle locking by yourself.
  config.lock_strategy = :failed_attempts

  # Defines which key will be used when locking and unlocking an account
  config.unlock_keys = [ :email ]
  # config.unlock_keys = [ :time ]

  config.unlock_strategy = :both
  # config.unlock_strategy = :time

  config.maximum_attempts = 3

  config.unlock_in = 2.hour

  # config.last_attempt_warning = false

  config.reset_password_within = 24.hours

  # config.encryptor = :sha512

  config.sign_out_via = :delete

end

我的管理员模型:

class Admin < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable, :lockable
end

我在管理员上添加可锁定的迁移:

class AddLockableToAdmin < ActiveRecord::Migration
  def change
    add_column :admins, :failed_attempts, :integer, default: 0
    add_column :admins, :unlock_token, :string
    add_column :admins, :locked_at, :datetime
  end
end

我的路线.rb:

devise_for :admins

【问题讨论】:

  • 愚蠢的问题,但是您是否尝试重新启动您的 Rails 服务器?
  • 在重新启动 Rails 服务器并调试代码后离开课程 @Ariejan 我已发布问题以获得帮助
  • 你让这些东西工作了吗?
  • 在 3 次登录尝试失败后,检查 rails console 是否设置了特定 Admin 用户的 failed_attempts 计数。请在问题中分享结果。

标签: ruby-on-rails ruby ruby-on-rails-3 devise


【解决方案1】:

第 1 步:验证设备是否已正确安装

1-您在迁移的failed_attempts 字段中缺少null: false

add_column :admins, :failed_attempts, :integer, default: 0, null: false

修复它并重新运行迁移

2- 更新控制台中的所有现有记录:

Admin.update_all failed_attempts: 0

3- 关闭您的服务器、控制台和其他任何使用或预加载您的应用程序的东西(spring、zeus 等...)

4- 在您的 Rails 控制台中,验证设备是否已正确安装

Admin.new.respond_to? :failed_attempts 应该返回 true

5- 仍然在您的控制台中,验证 Admin 是否可以手动锁定:

Admin.first.lock_access!

您应该会看到 SQL 正在更新您记录的 locked_atunlock_token 字段

6-启动您的服务器并再次尝试输入错误的密码(使用您手动锁定的另一个用户),看看failed_attempts的值是否改变

=> 结果:一切正常,但使用错误凭据登录不会增加 failed_attempts


第 2 步:验证设计失败的地方

暴力调试

我不知道你有没有调试器,所以我们将临时编辑负责递增failed_attempts 的方法,看看它在哪里停止。在 devise gem 中打开文件“lib/devise/models/lockable.rb”并像这样编辑它:

def valid_for_authentication?
  puts 'mark 1'
  return super unless persisted? && lock_strategy_enabled?(:failed_attempts)
  puts 'mark 2'

  # Unlock the user if the lock is expired, no matter
  # if the user can login or not (wrong password, etc)
  unlock_access! if lock_expired?

  if super && !access_locked?
    puts 'mark 3 (you should not see me)'
    true
  else
    puts 'mark 4 (you are supposed to see me)'
    self.failed_attempts ||= 0
    self.failed_attempts += 1
    if attempts_exceeded?
      puts 'mark 5 (you should not see me)'
      lock_access! unless access_locked?
    else
      puts 'mark 6 (you are supposed to see me)'
      save(validate: false)
    end
    false
  end
end

如您所见,我添加了“标记”以查看执行通过的位置。请注意,根据您的设计版本,方法的内容可能会略有不同,您只需添加“标记”即可。

重新启动服务器,尝试使用不正确的凭据登录,然后查看控制台以查看显示的标记。

经过我们的测试,您可以还原此文件以删除标记​​p>

=> 结果:使用错误凭据登录时,控制台中不显示任何标记

在控制台Admin.first.valid_for_authentication?中执行

=> 结果:显示标记 1、2、4、6,并在数据库中增加 failed_attempts


解决方案(仍有待确认)

用于身份验证的表单有一个action 值,它不会重定向到设计控制器。您似乎正在使用 api_console 生成身份验证表单。

【讨论】:

  • 感谢@Benjamin 提供非常干净的分步回答。我尝试按照这些步骤操作,成功完成了 1 到 5 个步骤。在第 6 步服务器启动时,我多次输入错误的凭据,但 failed_attempts 仍然显示 0,用户仍然处于活动状态未锁定。 (:
  • 是的。 irb(main):001:0> Admin.lock_strategy => :failed_attempts
  • 顺便说一句,我在第 4 步和第 5 步中错误地使用了User 而不是Admin,我假设您在测试期间修复了这个问题。另外,如果您输入正确的凭据,是否可以登录?
  • 是的,我明白,我使用的是管理员而不是用户。使用正确的凭据管理员登录工作正常。
  • (我打赌你有一个验证问题,我们会在你回答后看到)
【解决方案2】:

在听从 Benj 的建议后,我没能成功。在调试 lib/devise/models/lockable.rb 时,代码进入了if super &amp;&amp; !access_locked? 条件。

原来我的问题出在登录过程中,我错误地使用了valid_for_authentication? 函数。 IE。我做了类似的检查:

if user.valid_for_authentication? && user.valid_password?(params[:password])

而不是在一个块中提供密码验证:

if user.valid_for_authentication? { user.valid_password?(params[:password]) }

【讨论】:

    【解决方案3】:

    我遇到了同样的问题。但我通过这些步骤解决了

    1. 运行 rails g migration add_lockable_to_devise

    2. 在 db/migrate/***********_add_lockable_to_devise 中添加以下代码

      def up
       add_column :users, :failed_attempts, :integer
       add_column :users, :unlock_token, :string
       add_column :users, :locked_at, :datetime
      
       add_index :users, :unlock_token, unique: true
      
       execute("UPDATE users SET confirmed_at = NOW()")
      end
      
      def down
        remove_columns :users, :failed_attempts, :unlock_token, :locked_at  
      end
      

    3. 之后运行 rake db:migrate

    别忘了第 3 步

    【讨论】:

      【解决方案4】:

      我遇到了类似的问题,我通过这次迁移重新创建了表。

      试试这个:

      change_table(:admins) do |t|
        t.lockable :lock_strategy => :failed_attempts, :unlock_strategy => :both
      end
      

      【讨论】:

      • 感谢@Dave 的回答。我按照你的建议做了同样的事情,但得到了错误 - #<:connectionadapters::table:0x9a4bd80> 的未定义方法 `lockable'
      • 问题,可能是迁移文件具有列名而不是设计方法名。检查一次。
      • 似乎 admins 表不存在。你删除它了吗...如果是这样,重新创建表并在迁移文件中运行上面的代码。
      • 重新创建表。上面的迁移脚本是 - * def change change_table(:admins) do |t| t.lockable :lock_strategy => :failed_attempts, :unlock_strategy => :both end end *
      • t.lockable 在旧版本的 Devise 中可用,但在 Devise v 3.2.4 中不可用,这就是为什么 OP 在 #<:connectionadapters::>undefined method lockable' 错误Table:0x9a4bd80>` 使用你的答案。
      【解决方案5】:

      这是一个棘手的案例,我帮不了你太多,但可以指导你帮助自己。

      Devise 在https://github.com/plataformatec/devise/blob/master/lib/devise/models/lockable.rb 第 92 行更新 failed_attempts 计数。

      def valid_for_authentication?
          return super unless persisted? && lock_strategy_enabled?(:failed_attempts)
      
          # Unlock the user if the lock is expired, no matter
          # if the user can login or not (wrong password, etc)
          unlock_access! if lock_expired?
      
          if super && !access_locked?
            true
          else
            self.failed_attempts ||= 0
            self.failed_attempts += 1
            if attempts_exceeded?
              lock_access! unless access_locked?
            else
              save(validate: false)
            end
            false
          end
        end
      

      您必须编辑已安装 gem 的相应文件并添加一个记录器或对标准输出执行 puts 以查看 else 循环是否被执行。唯一可能的原因是当第一行 return 被调用时。

      我认为如果不深入研究设计代码就无法解决这个问题,因为你的配置是正确的。

      【讨论】:

      • 修改 gem 本身有点棘手,我还是试试吧。
      • 我遇到了同样的问题,但每次我尝试使用错误的凭据输入时,代码都会输入“if super && !access_locked?”并返回 true.. 我不知道为什么.. 有什么想法吗?
      猜你喜欢
      • 1970-01-01
      • 2018-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多