Monday, September 7, 2009

Adding Restful_Authentication to all controllers (by placing in application controller)

In short add

before_filter :login_required

to ApplicationController. Then throw in an exception in SessionsController that says

before_filter :login_required, :except => [:new, :create, :destroy]

Here's the excerpt from:

http://www.erikjacobs.com/2008/12/03/authenticating-all-controllers-for-your-rails-application-with-restful_authentication/

So while this might seem intuitive, I found it a little tricky. Preliminary Google searching didn’t reveal anything inherently obvious. However, robbrit on Freenode was able to lend me a hand and I got it figured out.


As you might expect, restful_authentication’s before_filter, :login_required, will direct you to the sessions controller if you are not logged in. So, I initially applied this before_filter to the entire application by placing it as the first line in app/controllers/application_controller.rb


class ApplicationController < ActionController::Base
  before_filter :login_required

Unfortunately, this had unintended consequences. Because this requires login for *all* controllers and *all* actions, we find that we are caught in an endless loop. The login route sends us to /sessions/new, but since we are not logged in, this action tries to again send us to login. Oops!


Rails is kind enough to allow for some exceptions and other fun with filters. So, I initially realized that we should probably add an exception for the “new” action, since that is where we are redirected for a login. We add this exception by re-iterating the before_filter in the app/controllers/sessions_controller.rb:


class SessionsController < ApplicationController
  before_filter :login_required, :except => :new

Unfortunately, this did not quite cut it entirely. Do not forget that the new action essentially just renders the login form. The create action is where all of the *real* work is done. But, since we did not except create, we end up in a login loop. We can fill out the form, press the “login” button, but when we reach the create action we are not logged in. This causes the filter to fire off and send us back to… you guessed it… the new action.

Adding an additional exception (and destroy, just in case) provides the results we are looking for:


class SessionsController < ApplicationController
  before_filter :login_required, :except => [:new, :create, :destroy]

Hopefully all of this stuff will work for you, too. This is just one way I found to authenticate all controllers with restful_authentication as I had a particular application that we wanted to lock down. The extra fun with this type of stuff is that you could put a before_filter on the signup actions. This would have the effect of only allowing a user with an existing account to create new users. This is useful for development lockdown to a certain extent.

No comments: