Useful Rails plugin: acts_as_authenticated

acts_as_authenticated

Installation

[code]
script/plugin source http://svn.techno-weenie.net/projects/plugins
script/plugin install acts_as_authenticated
script/generate authenticated user account
rake migrate
rake db:test:clone_structure
[/code]
(Note: The last line may not be necessary. AFAIK running a test using rake causes db:test:prepare to be run which clones the dev database to the test dataabse and populates it from the fixtures. Maybe it is needed if the test is to be run directly)
This generates a model called user and a controller called AccountController, their tests, views for account, a new module “AuthenticatedSystem” in the lib directory and a migration file to generate the necessary user table in the db.
In order to make authentication available to all controllers, move the line include AuthenticatedSystem from account_controller.rb to application.rb. To make the tests provided by acts_as_authenticated available move the line include AuthenticatedTestHelper from test/functional/account_controller_test.rb to testhelper.rb

Setup

Authentication is enabled using a before filter. This can be done on a per controller basis, but if there are many controllers then it might be better to make them all sub classes of an admin class that contains the before filter and looks something like this:
[ruby]
class Admin::BaseController < ApplicationController before_filter :login_required end [/ruby] This means that authentication is required for all methods of all controllers that are subclasses of the base controller. Finer grained control is possible if necessary using filters like these: [ruby] before_filter :login_required, :except => [:index]
before_filter :login_required, :only => :admin_action
[/ruby]

The current version (Dec24 06) of acts_as_authenticated has been modified to use rails 1.2 which isn’t out yet. Run edge rails or in views/login.rhtml the form_tag stuff needs changing back to the version that rails 1.1 understands.
[ruby]
#these lines:
<% form_tag do -%>
….
<% end -%>

#change to:
<%= start_form_tag %>
….
<%= end_form_tag %>

[/ruby]

Further modifications

There is no login failure message. Add a line near the end of the login method of AccountController like this:
[ruby]
def login
return unless request.post?
self.current_user = User.authenticate(params[:login], params[:password])
if logged_in?
if params[:remember_me] == “1”
self.current_user.remember_me
cookies[:auth_token] = { :value => self.current_user.remember_token , :expires => self.current_user.remember_token_expires_at }
end
redirect_back_or_default(:controller => ‘/account’, :action => ‘index’)
flash[:notice] = “Logged in successfully”
end
flash.now[:notice]= “Incorrect login”
end
[/ruby]
Add a login/logout link somewhere. The header of the layout file might be a good spot.
[ruby]

<% if logged_in? %>
Logged in as <%= current_user.login % (<%= link_to "logout", :controller => “/account”, :action => “logout” %>)
<% else %>
<%= link_to "login", :controller => “/account”, :action => “login” %>
<% end %>

[/ruby]
Note the if statement. In the eCommerce book it is given as this:
[ruby]
<% if current_user %>
…..
[/ruby]
But this doesn’t consistently work correctly. Not sure why, but sometimes current_user appears to have the value false, but the if statement is still executed. Weird, but using logged_in? instead of current_user seems to fix it.

Security Model

As installed, there are no limitations on who can register for an account. All it takesw is to go to http://mysite/accounts/signup and fill in some details. Some kind of checking is obviously needed here. The simplest method is just to restrict signup so it can only be accessed by a logged in user. Do this by adding this line to the beginning of the AccountController class.
[ruby]
before_filter :login_required, :only => :signup
[ruby/]
This would not be a good model for a site that needed to allow the public to log in, but would be entirely appropriate for an admin section of a site. The owner would need to create further logins themself in order to deputise admin functions..

Login while developing

Each time the migrations are re-run to encompass a change, the user in the database will be cleared out. This can be re-added every time. Commenting out this line in AccountController.rb will allow access to the signup page:
[ruby]
before_filter :login_required, :only => :signup
[/ruby]
alternatively get the migration to add in a default user:

You must be logged in to post a comment.