module Devise::Models::Lockable
def self.required_fields(klass)
def self.required_fields(klass) attributes = [] attributes << :failed_attempts if klass.lock_strategy_enabled?(:failed_attempts) attributes << :locked_at if klass.unlock_strategy_enabled?(:time) attributes << :unlock_token if klass.unlock_strategy_enabled?(:email) attributes end
def access_locked?
def access_locked? !!locked_at && !lock_expired? end
def active_for_authentication?
Overwrites active_for_authentication? from Devise::Models::Activatable for locking purposes
def active_for_authentication? super && !access_locked? end
def attempts_exceeded?
def attempts_exceeded? self.failed_attempts >= self.class.maximum_attempts end
def if_access_locked
Checks whether the record is locked or not, yielding to the block
def if_access_locked if access_locked? yield else self.errors.add(Devise.unlock_keys.first, :not_locked) false end end
def inactive_message
Overwrites invalid_message from Devise::Models::Authenticatable to define
def inactive_message access_locked? ? :locked : super end
def increment_failed_attempts
def increment_failed_attempts self.class.increment_counter(:failed_attempts, id) reload end
def last_attempt?
def last_attempt? self.failed_attempts == self.class.maximum_attempts - 1 end
def lock_access!(opts = { })
when you lock access, you could pass the next hash
* +opts+: Hash options if you don't want to send email
Lock a user setting its locked_at to actual time.
def lock_access!(opts = { }) self.locked_at = Time.now.utc if unlock_strategy_enabled?(:email) && opts.fetch(:send_instructions, true) send_unlock_instructions else save(validate: false) end end
def lock_expired?
def lock_expired? if unlock_strategy_enabled?(:time) locked_at && locked_at < self.class.unlock_in.ago else false end end
def resend_unlock_instructions
def resend_unlock_instructions if_access_locked { send_unlock_instructions } end
def reset_failed_attempts!
def reset_failed_attempts! if respond_to?(:failed_attempts) && !failed_attempts.to_i.zero? self.failed_attempts = 0 save(validate: false) end end
def send_unlock_instructions
def send_unlock_instructions raw, enc = Devise.token_generator.generate(self.class, :unlock_token) self.unlock_token = enc save(validate: false) send_devise_notification(:unlock_instructions, raw, {}) raw end
def unauthenticated_message
def unauthenticated_message # If set to paranoid mode, do not show the locked message because it # leaks the existence of an account. if Devise.paranoid super elsif access_locked? || (lock_strategy_enabled?(:failed_attempts) && attempts_exceeded?) :locked elsif lock_strategy_enabled?(:failed_attempts) && last_attempt? && self.class.last_attempt_warning :last_attempt else super end end
def unlock_access!
def unlock_access! self.locked_at = nil self.failed_attempts = 0 if respond_to?(:failed_attempts=) self.unlock_token = nil if respond_to?(:unlock_token=) save(validate: false) end
def valid_for_authentication?
for verifying whether a user is allowed to sign in or not. If the user
Overwrites valid_for_authentication? from Devise::Models::Authenticatable
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 increment_failed_attempts if attempts_exceeded? lock_access! unless access_locked? else save(validate: false) end false end end