Module: Devise::Models::Lockable

Extended by:
ActiveSupport::Concern
Defined in:
lib/devise/models/lockable.rb

Overview

Handles blocking a user access after a certain number of attempts. Lockable accepts two different strategies to unlock a user after it’s blocked: email and time. The former will send an email to the user when the lock happens, containing a link to unlock it’s account. The second will unlock the user automatically after some configured time (ie 2.hours). It’s also possible to setup lockable to use both email and time strategies.

Options

Lockable adds the following options to devise_for:

* +maximum_attempts+: how many attempts should be accepted before blocking the user.
* +lock_strategy+: lock the user account by :failed_attempts or :none.
* +unlock_strategy+: unlock the user account by :time, :email, :both or :none.
* +unlock_in+: the time you want to lock the user after to lock happens. Only available when unlock_strategy is :time or :both.
* +unlock_keys+: the keys you want to use when locking and unlocking an account

Defined Under Namespace

Modules: ClassMethods

Instance Method Summary collapse

Instance Method Details

#access_locked?Boolean

Verifies whether a user is locked or not.

Returns:

  • (Boolean)


46
47
48
# File 'lib/devise/models/lockable.rb', line 46

def access_locked?
  locked_at && !lock_expired?
end

#active_for_authentication?Boolean

Overwrites active_for_authentication? from Devise::Models::Activatable for locking purposes by verifying whether a user is active to sign in or not based on locked?

Returns:

  • (Boolean)


62
63
64
# File 'lib/devise/models/lockable.rb', line 62

def active_for_authentication?
  super && !access_locked?
end

#inactive_messageObject

Overwrites invalid_message from Devise::Models::Authenticatable to define the correct reason for blocking the sign in.



68
69
70
# File 'lib/devise/models/lockable.rb', line 68

def inactive_message
  access_locked? ? :locked : super
end

#lock_access!Object

Lock a user setting it’s locked_at to actual time.



26
27
28
29
30
31
32
33
34
35
# File 'lib/devise/models/lockable.rb', line 26

def lock_access!
  self.locked_at = Time.now

  if unlock_strategy_enabled?(:email)
    generate_unlock_token
    send_unlock_instructions
  end

  save(:validate => false)
end

#resend_unlock_tokenObject

Resend the unlock instructions if the user is locked.



56
57
58
# File 'lib/devise/models/lockable.rb', line 56

def resend_unlock_token
  if_access_locked { send_unlock_instructions }
end

#send_unlock_instructionsObject

Send unlock instructions by email



51
52
53
# File 'lib/devise/models/lockable.rb', line 51

def send_unlock_instructions
  ::Devise.mailer.unlock_instructions(self).deliver
end

#unlock_access!Object

Unlock a user by cleaning locket_at and failed_attempts.



38
39
40
41
42
43
# File 'lib/devise/models/lockable.rb', line 38

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

#valid_for_authentication?Boolean

Overwrites valid_for_authentication? from Devise::Models::Authenticatable for verifying whether a user is allowed to sign in or not. If the user is locked, it should never be allowed.

Returns:

  • (Boolean)


75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/devise/models/lockable.rb', line 75

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?

  case (result = super)
  when Symbol
    return result
  when TrueClass
    self.failed_attempts = 0
    save(:validate => false)
  when FalseClass
    # PostgreSQL uses nil as the default value for integer columns set to 0
    self.failed_attempts ||= 0
    self.failed_attempts += 1
    if attempts_exceeded?
      lock_access!
      return :locked
    else
      save(:validate => false)
    end
  end

  result
end