我已经在两个用户帐户Admin和Customer上实现了Devise。注册sign_in函数工作正常。我正在尝试在管理员帐户上实现可锁定。我正在使用Devise 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
我的routes.rb:
devise_for :admins
答案 0 :(得分:5)
步骤1:验证设备是否已正确安装
1 - 您在迁移的null: false
字段中遗漏了failed_attempts
。
add_column :admins, :failed_attempts, :integer, default: 0, null: false
修复它并重新运行迁移
2 - 更新控制台中的所有现有记录:
Admin.update_all failed_attempts: 0
3 - 关闭服务器,控制台以及使用或预装应用程序的任何其他内容(spring,zeus等...)
在rails控制台中4 - ,验证设备是否已正确安装
Admin.new.respond_to? :failed_attempts
应该返回true
5 - 仍在您的控制台中,验证是否可以手动锁定Admin
:
Admin.first.lock_access!
您应该会看到记录的SQL更新locked_at
和unlock_token
字段
6 - 启动服务器并再次输入错误的密码(使用其他用户手动锁定的用户),查看failed_attempts
的值是否发生变化
=&GT;结果:所有工作,但使用错误的凭据登录不会增加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>
=&GT;结果:在使用错误凭据登录期间,控制台中没有显示任何标记
在控制台Admin.first.valid_for_authentication?
=&GT;结果:显示标记1,2,4,6,并在数据库中增加failed_attempts
解决方案(仍有待确认)
用于身份验证的表单具有action
值,该值不会重定向到设计控制器。您似乎正在使用生成身份验证表单的api_console
。
答案 1 :(得分:3)
在遵循Benj的建议之后,我没能让它发挥作用。调试 lib / devise / models / lockable.rb 时,代码进入if super && !access_locked?
条件。
事实证明我的问题出在登录程序中,我错误地使用了valid_for_authentication?
函数。即我做了类似的检查:
if user.valid_for_authentication? && user.valid_password?(params[:password])
而不是在块中提供密码验证:
if user.valid_for_authentication? { user.valid_password?(params[:password]) }
答案 2 :(得分:1)
我有类似的问题,我通过此迁移重新创建了表。
试试这个:
change_table(:admins) do |t|
t.lockable :lock_strategy => :failed_attempts, :unlock_strategy => :both
end
答案 3 :(得分:1)
我遇到了同样的问题。但是我通过这些步骤解决了
运行 rails g migration add_lockable_to_devise
在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()")
端
确定 remove_columns:users,:failed_attempts,:unlock_token,:locked_at
端
3.运行 rake db:migrate
之后别忘了第3步
答案 4 :(得分:0)
这是一个棘手的案例,我可以为你提供很多帮助,但可以指导你自己帮助。
设计更新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的相应文件,并添加一个记录器或执行put到stdout以查看是否执行了else循环。它不会成功的唯一可能原因是第一行返回被调用。
我认为你不能深入研究设计代码就可以解决这个问题,因为你的配置是正确的。