Rajkumar Ulaganadhan
Rajkumar Ulaganadhan

Reputation: 708

How to use Devise lockable functionality outside of devise controller or method?

I want to lock the user after 5 multiple attempts in my application. So it is working when i use devise lockable. But i want to use it for API method except default action.

when i am using devise controller & model it is working

devise :database_authenticatable, :registerable, :lockable

user_sign_in method in my controller #using own method not working in my controller

  if user.first.valid_password?(params[:password])
    user.update_attributes(current_sign_in_at: DateTime.current)

    success_response(:ok, user, message: 'success message')
  else

    error_response(412, nil, 'failure message')
  end

in routes

post '/user_sign_in' => 'api/users#user_sign_in'

if i am using api call 'user_sign_in' method. It is not updating devise lockable method. How to trigger devise method in API?

Upvotes: 1

Views: 1343

Answers (3)

zeitnot
zeitnot

Reputation: 1314

To increment lock count you would use user.increment_failed_attempts. However, to see whether the user is locked or not you would use user.access_locked?. The sample code is here:

if user.access_locked?
  return redirect_to root_path, alert: 'Your account is locked'
end

unless user.valid_password?(params[:password])
 if Devise.maximum_attempts <= user.increment_failed_attempts
   user.lock_access!(send_instructions: true)
 end
 user.save(validate: false)  
end 

Upvotes: 1

Rajkumar Ulaganadhan
Rajkumar Ulaganadhan

Reputation: 708

I have added /lib/devise/models/lockable.rb files in my application. i have used the below methods based on my lockable functionalities. It is working fine.

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 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 access_locked?
    !!locked_at && !lock_expired?
  end

  def increment_failed_attempts
    self.class.increment_counter(:failed_attempts, id)
    reload
  end

   def unlock_access_by_token(unlock_token)
      original_token = unlock_token
      unlock_token   = Devise.token_generator.digest(self, :unlock_token, unlock_token)

      lockable = find_or_initialize_with_error_by(:unlock_token, unlock_token)
      lockable.unlock_access! if lockable.persisted?
      lockable.unlock_token = original_token
      lockable
    end

Upvotes: 1

Ranjith Rana
Ranjith Rana

Reputation: 164

#You Can Try this way. It will work Perfectly

if user.failed_attempts >= Devise.maximum_attempts
            user.lock_access!(send_instructions: true)
    else
            user.increment_failed_attempts
end

Upvotes: 2

Related Questions