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 its account. The second will unlock the user automatically after some configured time (ie 2.hours). It’s also possible to set up lockable to use both email and time strategies.
Options
Lockable adds the following options to devise
:
* +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
Class Method Summary collapse
Instance Method Summary collapse
-
#access_locked? ⇒ Boolean
Verifies whether a user is locked or not.
-
#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?.
- #attempts_exceeded? ⇒ Boolean protected
-
#if_access_locked ⇒ Object
protected
Checks whether the record is locked or not, yielding to the block if it’s locked, otherwise adds an error to email.
-
#inactive_message ⇒ Object
Overwrites invalid_message from Devise::Models::Authenticatable to define the correct reason for blocking the sign in.
- #last_attempt? ⇒ Boolean protected
-
#lock_access!(opts = { }) ⇒ Object
Lock a user setting its locked_at to actual time.
-
#lock_expired? ⇒ Boolean
protected
Tells if the lock is expired if :time unlock strategy is active.
-
#resend_unlock_instructions ⇒ Object
Resend the unlock instructions if the user is locked.
-
#send_unlock_instructions ⇒ Object
Send unlock instructions by email.
- #unauthenticated_message ⇒ Object
-
#unlock_access! ⇒ Object
Unlock a user by cleaning locked_at and failed_attempts.
-
#valid_for_authentication? ⇒ Boolean
Overwrites valid_for_authentication? from Devise::Models::Authenticatable for verifying whether a user is allowed to sign in or not.
Class Method Details
.required_fields(klass) ⇒ Object
27 28 29 30 31 32 33 34 |
# File 'lib/devise/models/lockable.rb', line 27 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 |
Instance Method Details
#access_locked? ⇒ Boolean
Verifies whether a user is locked or not.
59 60 61 |
# File 'lib/devise/models/lockable.rb', line 59 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?
79 80 81 |
# File 'lib/devise/models/lockable.rb', line 79 def active_for_authentication? super && !access_locked? end |
#attempts_exceeded? ⇒ Boolean (protected)
129 130 131 |
# File 'lib/devise/models/lockable.rb', line 129 def attempts_exceeded? self.failed_attempts >= self.class.maximum_attempts end |
#if_access_locked ⇒ Object (protected)
Checks whether the record is locked or not, yielding to the block if it’s locked, otherwise adds an error to email.
148 149 150 151 152 153 154 155 |
# File 'lib/devise/models/lockable.rb', line 148 def if_access_locked if access_locked? yield else self.errors.add(Devise.unlock_keys.first, :not_locked) false end end |
#inactive_message ⇒ Object
Overwrites invalid_message from Devise::Models::Authenticatable to define the correct reason for blocking the sign in.
85 86 87 |
# File 'lib/devise/models/lockable.rb', line 85 def access_locked? ? :locked : super end |
#last_attempt? ⇒ Boolean (protected)
133 134 135 |
# File 'lib/devise/models/lockable.rb', line 133 def last_attempt? self.failed_attempts == self.class.maximum_attempts - 1 end |
#lock_access!(opts = { }) ⇒ Object
Lock a user setting its locked_at to actual time.
-
opts
: Hash options if you don’t want to send email when you lock access, you could pass the next hash ‘{ send_instructions: false } as option`.
40 41 42 43 44 45 46 47 48 |
# File 'lib/devise/models/lockable.rb', line 40 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 |
#lock_expired? ⇒ Boolean (protected)
Tells if the lock is expired if :time unlock strategy is active
138 139 140 141 142 143 144 |
# File 'lib/devise/models/lockable.rb', line 138 def lock_expired? if unlock_strategy_enabled?(:time) locked_at && locked_at < self.class.unlock_in.ago else false end end |
#resend_unlock_instructions ⇒ Object
Resend the unlock instructions if the user is locked.
73 74 75 |
# File 'lib/devise/models/lockable.rb', line 73 def resend_unlock_instructions if_access_locked { send_unlock_instructions } end |
#send_unlock_instructions ⇒ Object
Send unlock instructions by email
64 65 66 67 68 69 70 |
# File 'lib/devise/models/lockable.rb', line 64 def send_unlock_instructions raw, enc = Devise.token_generator.generate(self.class, :unlock_token) self.unlock_token = enc self.save(validate: false) send_devise_notification(:unlock_instructions, raw, {}) raw end |
#unauthenticated_message ⇒ Object
113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/devise/models/lockable.rb', line 113 def # 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 |
#unlock_access! ⇒ Object
Unlock a user by cleaning locked_at and failed_attempts.
51 52 53 54 55 56 |
# File 'lib/devise/models/lockable.rb', line 51 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.
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/devise/models/lockable.rb', line 92 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 |