Devise: Registering log in attempts

2020-04-08 11:22发布

问题:

I have a Rails 3.0 project using devise and I've been requested to register in DB every succesful login and every failed attempt.

From the devise documentation I think I'd have to extend FailureApp but the examples are just redirecting users and not using the model at all. In stackoverflow I've just found this question but it remained unanswered, which is not encouraging

Can anyone tell me if I'm correct in this approach or it can't be done this way, or if there is some easier alternative I'm missing?

(I know there is no code yet, I'm just looking for a small guidance before diving in)

Thanks.

回答1:

Modifying Devise::SessionsController to do your dirty work will do the trick.

Simply copy that file into your app/controllers/devise/sessions_controller.rb

Once you've done that, just add some code to where the user successfully logs in and where he fails to log in that will do what you want.

You'll probably want to create a new model for tracking login records.



回答2:

Spent a little bit of time looking into this myself and figured someone else might find this useful.

The create action in the devise controller calls warden.authenticate!, which attempts to authenticate the user with the supplied params. If authentication fails then authenticate! will call the devise failure app, which then runs the SessionsController#new action. Note, any filters you have for the create action will not run if authentication fails.

So the solution is to add a filter after the new action which checks the contents of env["warden.options"] and takes the appropriate action.

e.g.

def instrument_failed_login
  instrument "failed_login.staff" if failed_login?
end

def failed_login?
  (options = env["warden.options"]) && options[:action] == "unauthenticated"
end


回答3:

An alternative and more maintainable way of adding logging around Devise authentication is to use the Warden Callbacks in an initializer. This is preferable because it uses the Warden API's designed for this and doesn't involve copy/pasting controller code.

Warden::Manager.before_failure do |env, opts|
    logger.error("opts[:scope] authentication failure: #{opts[:message]}")
end

You can do the same with Warden::Manager#after_authentication and Warden::Manager#before_logout.