Wednesday, January 09, 2008

Rails Hack: Combining Acts_As_Auth with Long-Lasting Anonymous Sessions

In one of my Rails apps, I have two kinds of users: anonymous visitors, who do not have to sign up at all to use the app's functionality, and "vendor" users, who need to sign up and create some content in order to get value from the site.

The requirement for sessions was simple:

Anonymous visitors should have a session that persists for a long time (e.g., months) via a cookie. Since there is no information at all collected from these visitors, there is no reason to clear them out of the browser, and they would appreciate the convenience of being able to pick up where they left off when they come back.

Vendor users, however, have more data at stake, and so should have the typical login/password/remember-me?/logout pattern, allowing them to decide if their sign-in should persist, and letting them explicitly logout to kill their authentication.

I dropped in acts_as_authenticated, and it does a fine job with the second case (vendors). For the first case, I then added sliding_sessions, which is elegant and has now been added to the relevant wiki page.

The problem is: once session cookie durations are extended in general (at the application or controller level), aaa's authenticated users will be "remembered" upon return to the site, whether they want to be or not -- because their user info is already in their session (i.e., the "login from cookie" is not necessary and is never called). Timing out a session/auth on the server side is a good practice, but doesn't solve this issue -- if the user closes the browser and walks away, someone might come up right behind them and come back to the site, where the session/auth has not timed out.

Here's my solution. It seemed quick and easy; if anyone has criticism or improvements, let me know:

There are three cases -- anonymous user; vendor asking to be "remembered"; and vendor not asking to be "remembered" -- of which the first two worked fine. So I add a cookie upon login, set to timeout at the end of the current session, which will help me separate out the third case.

The details:

AAA adds a couple of "account controller" actions to your app. In login, I added the new cookie (see line 11). Then, in application.rb, I added this method as a before_filter. It checks to see whether you are an authenticated user (i.e., not an anonymous visitor). If so, it resets the session unless it sees the vendor cookie (meaning you've signed in in this browser session and so should not be cleared out yet regardless of "remember me" choice) or the auth_token cookie (created by aaa, and indicating the the "remember me" persistent login choice).

So if you authenticate and do not choose "remember me" then you have no auth_token cookie and, when you close the browser, you lose your vendor cookie. When you come back to the site, your session (and user info) are cleared.

1 comment:

Anonymous said...

Nice!