Authlogic released! Rails authentication done right.October 25th, 2008The last thing we need is another authentication solution for rails, right? That's what I thought until I tried out some of the current solutions. None of them felt right. They were either too complicated, bloated, littered my application with tons of code, or were just confusing. This is not the simple / elegant rails we all fell in love with. We need a "rails like" authentication solution. Authlogic is my attempt to satisfy that need... What if you could have authentication up and running in minutes without having to run a generator? All because it's simple, like everything else in rails. What if creating a user session could be as simple as... UserSession.create(params[:user]) What if your user sessions controller could look just like your other controllers... class UserSessionsController < ApplicationController def new @user_session = UserSession.new end def create @user_session = UserSession.new(params[:user_session]) if @user_session.create redirect_to account_url else render :action => :new end end def destroy current_user_session.destroy end end Look familiar? If you didn't know any better, you would think UserSession was an ActiveRecord model. I think that's pretty cool. Why is that cool? Because it fits nicely into the RESTful development pattern and its a style we all know and love. Wouldn't this be cool too... <%= error_messages_for "user_session" %> <% form_for @user_session do |f| %> <%= f.label :login %><br /> <%= f.text_field :login %><br /> <br /> <%= f.label :password %><br /> <%= f.password_field :password %><br /> <br /> <%= f.submit "Login" %> <% end %> Or what about persisting the session... class ApplicationController helper_method :current_user_session, :current_user protected def current_user_session return @current_user_session if defined?(@current_user_session) @current_user_session = UserSession.find end def current_user return @current_user if defined?(@current_user) @current_user = current_user_session && current_user_session.user end end Authlogic makes this a reality. Reclaim your UsersControllerThis is one of my favorite features that I think its pretty cool. It's things like this that make a library great and let you know you are on the right track. Just to clear up any confusion, Authlogic does not store the plain id in the session. It stores a token. This token changes with the password, this way stale sessions can not be persisted. That being said..What if a user changes their password? You have to re-log them in with the new password, recreate the session, etc, pain in the ass. Or what if a user creates a new user account? You have to do the same thing. Here's an even better one: what if a user is in the admin area and changes his own password? There might even be another place passwords can change. It shouldn't matter, your code should be written in a way where you don't have to remember to do this. Instead of updating sessions all over the place, doesn't it make sense to do this at a lower level? Like the User model? You're saying "but Ben, models can't mess around with sessions and cookies". True...but Authlogic can, and you can access Authlogic just like a model. I know in most situations it's not good practice to do this but I view this in the same class as sweepers, and feel like it actually is good practice here. User sessions are directly tied to users, they should be connected on the model level. Fear not, because the acts_as_authentic method you call in your model takes care of this for you, by adding an after_create and after_update callback to automatically keep the session up to date. You don't have to worry about it anymore. Don't even think about it. Let your UsersController deal with users, not users AND sessions. ANYTIME the user changes his password in ANY way, his session will be updated. Here is basically what is done... class User < ActiveRecord::Base after_save :maintain_sessions! private def create_sessions! # create a new UserSession if they are not logged in end def maintain_sessions! # If we aren't logged in at all and the password was changed, go ahead and log the user in # If we are logged in and the password has change, update the sessions end end Obviously there is a little more to it than this, but hopefully this clarifies any confusion. When things come together like this I think its a sign that you are doing something right. Put that in your pipe and smoke it! Authlogic arouses meThat's great, here are some resources:
28 Responses to “Authlogic released! Rails authentication done right.”Leave a Reply |
SearchCategories |
Great work Ben. This is really cool, as is Searchgasm. But why are you using the “gasm” suffix for these? At the risk of getting flamed for being a retard, I can’t see myself using these plugins at work only because of the names. I know that sounds dumb, but I work for a fortune 500 and it would be a little awkward if I had to mention that we have an issue with the “Authgasm” plugin during a meeting. :-) I might be in the minority here, but I doubt I’m the only one who feels this way.
Any chance of reconsidering the naming convention on these plugins? :-)
Cheers, John
ummm, cool! I like this a lot.
Ha ha, thanks for your comments John. I can’t believe you don’t like the name. I spent hours coming up with it.
Honestly, I just thought it was funny, and I thought it was funny for that exact reason you mentioned. I could envision people bringing this up in discussions. I decided to use the name searchgasm and authgasm, because:
Regardless, it’s all in the delivery. If you don’t want to say “authgasm” in a meeting. Just say “binary logic’s authentication solution” or say “authentication solution”, or [insert enterprise appropriate name here].
Also, I went with authgasm for consistency and the fact that I really don’t care what it’s called. Just wanted something different than some ole boring name. How else am I going to get people’s attention on a plugin that deals with a solution that’s been “solved” a million times? Maybe once I get people’s attention I’ll change it. Got any suggestions?
RADR- pronounced RADAR.
Rails Authentication Done Right.
It all sounds good, but no test cases? Seriously? For something as important as authentication? That’s a total no-go for me.
Nice, looks really good!
John, what a ridiculous sample of american puritanism. All my prejudices about the strange country across the atlantic suddenly are nothings but true. ;)
Actually, I would call “authentication done right” for a plugin that leveraged out-of-the-box LDAP integration. I know, I am guilt too because I never contributed a LDAP solution. Does anyone know any authentication solution that already does that? Meaning: authenticates against Active Directory, for instance?
Why is the password being dragged around in the user’s session?
Why worry about when a use changes their password?
Seems like extra work to me.
An authn’ed user is authn’ed until they log out. If they changed their password during their last session, then they obviously need to log back in using their new password.
FB.
Mathais, that is why this is still in beta (0.X). I completed the tests last night and am about to release 0.10.0. And it’s not like I haven’t been testing this. Which is why I have no problems with any of the tests I wrote. The only way to test this is in a rails app. Rails provides ways to easily perform functional tests. Anyways, it’s all good now.
Frank, I’m confused. The password isn’t being dragged around. In fact, the password is not publicly accessible, period. When logging in via a session or a cookie a password isn’t even provided. If you don’t mind, please let me know what you are talking about. Thanks!
I refer to the exxerpt below: “What if a user changes their password? You have to re-log them in with the new password, recreate the session, etc, pain in the ass. Or what if a user creates a new user account? You have to do the same thing. Here’s an even better one: what if a user is in the admin area and changes his own password? There might even be another place passwords can change. It shouldn’t matter, your code should be written in a way where you don’t have to remember to do this.”
From that, I inferred that you were accounting to keeping the changed password synced back into the user record or session record. I made this inference based on the fact that you devoted more than a paragraph to the idea that a user loses their logged-in status by changing their password.
FB
Not a problem Frank. Yeah, the password is not kept around or stored anywhere. The only place it is stored is in the “crypted_password” field where it is…encryped, either via a hash or an encryption algorithm, based on your settings. All that I was talking about in that paragraph is updating the session and the “remember_token”, which is what the cookie holds.
What I’m saying is that the act of resetting a password is just a database update. I don’t see why you’d need or want to
“re-log them in with the new password, recreate the session, etc.”
I was asking where the need to take such drastic steps came from.
FB
Frank, I see what you are saying.
That being said you would need to update the session and the cookie with the new “token”.
Do you think you might be able to post something about how to integrate roles into this system? I think roles are something thats severely lacking in the rails community.
Why not use an observer to clear the sessions, instead of polluting the User model?
Hey Preston, you make a good point. But roles really have to do with the user their self, not really their session. All of the role systems I have implemented were extremely simple. I was under the impression there were some pretty good role plugins. Have you checked out the recipes in the “rails recipes” books. They have a good chapter on this.
Daniel, I agree 100%. But I am doing this from a library stand point. Making you create a UserObserver, adding it to your config.observers, then including an authgasm module is a lot more work than just calling acts_as_authentic in your User model. Observers are a way for you to organize your code. acts_as_authentic doesn’t “generate” more code, therefore it really doesn’t matter if its in an observer or the model, it’s all the same to you.
For roles, check out ACL2—really simple & effective: http://opensvn.csie.org/ezra/rails/plugins/dev/acl_system2/
I like the name. Keep it. If someone is too much of a sissy-la-la to use a tool just because of their name, that is their problem. I think keeping humor in the workplace is a good thing, and its an attribute of an agile programer. Agile like ninja. Agile ninjas have the ability to cut you down if you don’t like their naming conventions…..
Keep up the good work, as I am too busy having an orgasm from reading your Authgasm code.
What if users are divided into different accounts? For example, in case of SaaS, where an account is identified by the subdomain name. By a quick glance at the code, it seems that logins and email addresses wlll be unique through out the table. How about adding :scope_id for login and email address?
Something like
acts_as_authentic :scope_id => :account
Umair, you make a good point. I will add that in.
Ben, I assume many people will attempt to replace their restful_authentication with authgasm. I’d therefor suggest to focus on the differences between these two (are openid, verification emails, reset password email,... planned for authgasm?), plus adding a quick how-to for a migration. E.g. restful_auth created some conventions and convenience methods, such as current_user (but maybe other stuff too I can’t think of atm), and I doubt people really know what they’d need to do if they want to get rid of restful_authentication over the long term…
Umair, I released an update and hardcore scoped support is now added. I think its pretty nifty.
Alex, you make a really good point. I thought about all of those things, so here are my thoughts on each one:
1. OpenID: I do plan to add this in. This should be very simple and authlogic makes it easy.
2. Verification emails, reset password email: I feel like emails are really up to the application. The app might want to style them in a certain way, might want to reset passwords different, etc. I actually started a tutorial on how to reset passwords with authgasm. I just did it in a project of mine and it was extremely easy and simple. Authlogic has everything in place to make this easy. I also feel like that is something your app should handle, not a authlogic. They are fairly elementary tasks, and my tutorial should clarify this.
But you make some good points and I added “switching from restful_authentication” to my list of blog posts to do. Hopefully I can get that up this week, since it should be rather simple.
Thanks for your comments.
Thanks Ben, I can see you have made some well thought out changes. I’m going to try them out now. Will be helpful for an upcoming project.
I’m also glad for the name changes :)
Hello,
The plugin command is not working for me:
% script/plugin install git://github.com/binarylogic/authlogic.git Plugin not found: [“git://github.com/binarylogic/authlogic.git”] %
And I don’t seem to be able to use the gem version either b/c my version of rails complains that the config.gem method doesn’t exist.
Can someone kindly help me? Thanks!
From looking at example demo site you have. Changing the password doesn’t require typing the old password. I was wondering, what I need to do to retrieve the saved password and compare it to the old password just typed. Thanks.
Mabed, if you look in the docs for acts_as_authentic there is a valid_password?(password_hash) method you can use.
def update if current_user.valid_password?(params[:old_password]) current_user.password = params:user current_user.password_confirmation = params:user begin current_user.save! flash[:notice] = ‘Successfully changed your password.’ redirect_to account_url rescue ActiveRecord::RecordInvalid => e flash[:error] = “Couldn’t change your password: #{e}” end else flash[:notice] = “Couldn’t change your password: Either you’re old password is incorrect or the new password and confirmation aren’t the same” render :action => :edit end end