module Devise::Models::Lockable

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 setup 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

Public Instance Methods

access_locked?() click to toggle source

Verifies whether a user is locked or not.

# File lib/devise/models/lockable.rb, line 57
def access_locked?
  locked_at && !lock_expired?
end
active_for_authentication?() click to toggle source

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?

# File lib/devise/models/lockable.rb, line 73
def active_for_authentication?
  super && !access_locked?
end
inactive_message() click to toggle source

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

# File lib/devise/models/lockable.rb, line 79
def inactive_message
  access_locked? ? :locked : super
end
lock_access!() click to toggle source

Lock a user setting its locked_at to actual time.

# File lib/devise/models/lockable.rb, line 37
def lock_access!
  self.locked_at = Time.now.utc

  if unlock_strategy_enabled?(:email)
    generate_unlock_token!
    send_unlock_instructions
  else
    save(:validate => false)
  end
end
resend_unlock_token() click to toggle source

Resend the unlock instructions if the user is locked.

# File lib/devise/models/lockable.rb, line 67
def resend_unlock_token
  if_access_locked { send_unlock_instructions }
end
send_unlock_instructions() click to toggle source

Send unlock instructions by email

# File lib/devise/models/lockable.rb, line 62
def send_unlock_instructions
  send_devise_notification(:unlock_instructions)
end
unauthenticated_message() click to toggle source
# File lib/devise/models/lockable.rb, line 107
def unauthenticated_message
  if lock_strategy_enabled?(:failed_attempts) && attempts_exceeded?
    :locked
  else
    super
  end
end
unlock_access!() click to toggle source

Unlock a user by cleaning locked_at and failed_attempts.

# File lib/devise/models/lockable.rb, line 49
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?() click to toggle source

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.

# File lib/devise/models/lockable.rb, line 86
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

Protected Instance Methods

attempts_exceeded?() click to toggle source
# File lib/devise/models/lockable.rb, line 117
def attempts_exceeded?
  self.failed_attempts > self.class.maximum_attempts
end
generate_unlock_token() click to toggle source

Generates unlock token

# File lib/devise/models/lockable.rb, line 122
def generate_unlock_token
  self.unlock_token = self.class.unlock_token
end
generate_unlock_token!() click to toggle source
# File lib/devise/models/lockable.rb, line 126
def generate_unlock_token!
  generate_unlock_token && save(:validate => false)
end
if_access_locked() { || ... } click to toggle source

Checks whether the record is locked or not, yielding to the block if it’s locked, otherwise adds an error to email.

# File lib/devise/models/lockable.rb, line 141
def if_access_locked
  if access_locked?
    yield
  else
    self.errors.add(:email, :not_locked)
    false
  end
end
lock_expired?() click to toggle source

Tells if the lock is expired if :time unlock strategy is active

# File lib/devise/models/lockable.rb, line 131
def lock_expired?
  if unlock_strategy_enabled?(:time)
    locked_at && locked_at < self.class.unlock_in.ago
  else
    false
  end
end

Public Class Methods

required_fields(klass) click to toggle source
# 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 << :unlock_at if klass.unlock_strategy_enabled?(:time)
  attributes << :unlock_token if klass.unlock_strategy_enabled?(:email)

  attributes
end