public
Description: acts_as_authenticated Ruby on Rails authentication system
Home | Edit | New

User Authentication

User Authentication

The way the plugin works is simple. The first thing you do is create the models and migration:

script/generate authenticated user account

(In older versions of the plugin, you needed to create the migration separately:

script/generate authenticated_migration

This should no longer be necessary.)

This will not only create your User model, but an Account controller, some unit and functional1 tests, and some libraries in lib/. Once that’s done, you can move the include AuthenticatedSystem from app/controllers/account_controller.rb to app/controllers/application.rb. This makes all the authentication methods available to all controllers.
Requiring Authentication

To require logins for all actions, use this in your controllers:

before_filter :login_required, :except => [:login]

To require logins for specific actions, use this in your controllers:

before_filter :login_required, :only => [ :edit, :update ]

To skip this in a subclassed controller:

skip_before_filter :login_required

Here are other available methods for your views and controllers:

  • logged_in? – Returns true if the user is currently logged in.
  • current_user – Returns an instance of the currently logged in user.

You can override the #protect? method in your controller to only protect certain actions:

  1. don’t protect the login and the about method
    def protect?(action)
    if [‘login’, ‘about’].include?(action)
    return false
    else
    return true
    end
    end

You can also override #authorized? in your controller to restrict the actions based on the user:

  1. only allow nonbobs
    def authorized?(user)
    user.login != “bob”
    end

Note: there was a typo. It’s authorized? with a “d?”. The source code has a typo in the explanatory comments, too.
Question: How do you do both?

I have a controller that needs multiple levels of access control.

  • Some methods should be available to all viewers (view posts, etc.)
  • Some methods should only be available to viewers who have registered and are logged in (comments)
  • Some methods should only be available to logged-in users with the admin flag set on their id (delete, post, etc.)

I can, of course, refactor things into separate controllers, but I’m a bit confused on what happens to MVC when the view ends up with references to things in a different controller. What I used do to is have an “admin_required?” filter (I think I hacked it into authenticated_system.rb), but I lost it with a recent update of my copy of the plugin.
Answer

I needed the same thing, and I was able to accomplish it by accessing the action_name variable in the overridden authorized? method, like this:

  1. protect the new and create method for only admins
    def authorized?(user)
    if [‘new’, ‘create’].include?(action_name)
    return false unless user.is_admin?
    end
    return true
    end

You could refactor that (untested):

def authorized?(user) user.is_admin? || ![‘new’, ‘create’].include?(action_name) end

If your lib/authenticated_system.rb implementation of authorized? does not take a parameter, you must modify the method declaration above to avoid complaints about the method requiring one parameter but zero being given:

def authorized?(user = current_user()) … end

Another Answer

You can use

def authorized? return current_user.is_admin? end

so that you do not have to refactor lib/authenticated_system.rb

Another thing I found is that you may like to override access_denied method so that it returns an error mesage or HTTP Forbidden, instead of redirecting to the login page.
Tests

You need to include AuthenticatedTestHelper in test_helper.rb. The tests for actions in your controller using the :login_required filter will need to login before calling the action. One way to login is to use the fixture :users in the test class, then call login_as :quentin in either the test methods or setup method.
Tiny improvement

If the user fails to log in (say they forgot to activate the acct, or the password is bad), it would be nice to remember the login they entered. To do this, change the account_controller.rb

def login return unless request.post? @login = params[:login] #add this variable
  1. rest of method goes here
    end

then in the view login.rhtml, you can change the login field like so:

<%= text_field_tag ‘login’, @login %>

Last edited by gundestrup, Fri Oct 24 03:15:41 -0700 2008
Home | Edit | New
Versions: