Tutorial: Authlogic Basic SetupNovember 3rd, 2008I'm a machine today! 3 blog posts in one day. I can't be stopped. Anyways, this past week I released Authlogic and it has been great. I've been getting a lot of positive feedback and it seems like people enjoy using it. That's the reason I release any of my libraries, to try and make your life a little easier. Awwww, how sweet. But I've also been getting emails asking me to put together a setup tutorial. So here we go... What am I about to build?Why not check it out for yourself... A live example of this tutorialTo put it into words, we are going to setup basic user authentication for a new rails app. When it's all said and done, you will have an authentication system that provides:
Assumptions
Helpful links
Migrating an existing app from restful_authentication?It's simple, checkout my blog post about this. Also, keep reading this tutorial as this will help you understand the implementation. 1. Install AuthglogicInstall the gem / plugin (recommended) $ sudo gem install authlogic # config/environment.rb config.gem "authlogic" Or as a plugin (you must have git installed to do this) $ script/plugin install git://github.com/binarylogic/authlogic.git 2. Create your UserSession modelNow we need to create the user session model: $ script/generate session user_session This will create a file that looks like: # app/models/user_session.rb class UserSession < Authlogic::Session::Base # various configuration goes here, see AuthLogic::Session::Config for more details end Remember all of those repetitive authentication methods you added in your controllers? All of that "cruft" is taken care of in this file. It basically sits in between you and the cookies. Similar to how ActiveRecord sits in between you and the database. 3. Create your UserSessions controller$ script/generate controller user_sessions This is where people will be logging in / out. Name it after your UserSession model, just like you name all of your other controllers after your model. Map the resource in config/routes.rb: # config/routes.rb map.resource :user_session map.root :controller => "user_sessions", :action => "new" Now setup your UserSessionsController just like you would with a model: # app/controllers/user_sessions_controller.rb class UserSessionsController < ApplicationController def new @user_session = UserSession.new end def create @user_session = UserSession.new(params[:user_session]) if @user_session.save flash[:notice] = "Login successful!" redirect_back_or_default account_url else render :action => :new end end def destroy current_user_session.destroy flash[:notice] = "Logout successful!" redirect_back_or_default new_user_session_url end end What is going on here?
What is redirect_back_or_default? We will get to this method in a few steps and I will explain what it does there. So hold your horses. 4. Create and setup your User model$ script/generate scaffold user \ login:string \ crypted_password:string \ password_salt:string \ persistence_token:string \ login_count:integer \ last_request_at:datetime \ last_login_at:datetime \ current_login_at:datetime \ last_login_ip:string \ current_login_ip:string Every field, below persistence_token is a "magic" field. Authlogic will take care of keeping these up to date for you. They are optional, so add them if you want. They work the same way as created_at and updated_at. Another thing to keep in mind is that there are other optional token field. You can add a "singleaccesstoken" and a "perishable_token" that Authlogic will maintain for you. There are different types of access for accounts, as a result we need different types of tokens. Take resetting a password, accessing a private feed, etc. I won't repeat myself here, but for more information checkout the "tokens" section in the README. It's explained in more detail there. Now just run your migrations $ rake db:migrate Make your user act as authentic: # app/models/user.rb class User < ActiveRecord::Base acts_as_authentic end Basically acts_as_authentic adds all of the repetitive authentication code in your model:
Something to keep in mind is that by default Authlogic uses the Sha512 algorithm. you are NOT forced to use this, in fact Authlogic comes preloaded with some common encryption algorithms that you can choose from. I personally like the BCrypt method a lot. Let's say you wanted to use that instead. Just tell Authlogic about it: # app/models/user.rb class User < ActiveRecord::Base acts_as_authentic :crypto_provider => Authlogic::CryptoProviders::BCrypt end For more information on the available crypto providers, checkout the "Encryption methods" section in the read. Also, Authlogic provides a very easy way to migrate passwords to a new algorithm as well. As you can see, acts_as_authentic accepts a number of options. Checkout Authlogic::ORMAdapters::ActiveRecordAdapter::ActsAsAuthentic::Config in the documentation for more details. 5. Create your UsersControllerFirst let's set up some routes. Add these above your other routes: # config/routes.rb map.resource :account, :controller => "users" map.resources :users Basically registrations and the "my account" area are using the same controller: UsersController. The last generator you ran should have added app/controllers/users_controller.rb. This is a typical CRUD controller, nothing new. But let's go ahead and modify it to look like the following: # app/controllers/users_controller.rb class UsersController < ApplicationController def new @user = User.new end def create @user = User.new(params[:user]) if @user.save flash[:notice] = "Account registered!" redirect_back_or_default account_url else render :action => :new end end def show @user = @current_user end def edit @user = @current_user end def update @user = @current_user # makes our views "cleaner" and more consistent if @user.update_attributes(params[:user]) flash[:notice] = "Account updated!" redirect_to account_url else render :action => :edit end end end Let's talk a little bit about this controller:
6. Setup your viewsThe views are very simple and don't introduce anything new, but obviously are necessary to get this app running. So instead of cluttering up this tutorial with all of the views, check out the source code. You can copy the views from that very easily. Here is a direct link to the views folder. 7. Setup your ApplicationControllerYour application controller will be responsible for persisting your session. This is my favorite part because it is so easy. I am able to do in 2 methods what used to take 5 to 6 different methods: # app/controllers/application.rb class ApplicationController < ActionController::Base filter_parameter_logging :password, :password_confirmation helper_method :current_user_session, :current_user private 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 Keep in mind this is just a tutorial. You can accomplish the above any way you want. Authlogic lets you design your app how you want. 8. Restrict accessThis is done the same way you have always restricted access. Here is how I do it. Add this into your ApplicationController: # app/controllers/application.rb class ApplicationController < ActionController::Base private def require_user unless current_user store_location flash[:notice] = "You must be logged in to access this page" redirect_to new_user_session_url return false end end def require_no_user if current_user store_location flash[:notice] = "You must be logged out to access this page" redirect_to account_url return false end end def store_location session[:return_to] = request.request_uri end def redirect_back_or_default(default) redirect_to(session[:return_to] || default) session[:return_to] = nil end end You will notice I added in some extra methods that you have probably seen before: store_location and redirect_back_or_default. These are pretty self explanatory, but they basically allow you to redirect the user back to where they were trying to go initially. For example, if they tried to access their account while logged out it would store that location and redirect them to their account once they logged in. Now its time to restrict access. Add the following code: # app/controllers/user_sessions_controller.rb class UserSessionsController < ApplicationController before_filter :require_no_user, :only => [:new, :create] before_filter :require_user, :only => :destroy end Now for your users controller: # app/controllers/users_controller.rb class UsersController < ApplicationController before_filter :require_no_user, :only => [:new, :create] before_filter :require_user, :only => [:show, :edit, :update] end You're done! You now have a working rails app with authentication.If you go back through this tutorial you will notice you really didn't learn anything new. Creating RESTful routes and controllers is something you already knew. If anything this tutorial made you "unlearn" mundane tasks you had to previously perform with other authentication solutions. Next StepsYou might be asking any of the following questions:
I will answer your questions in order:
FeedbackIf you enjoyed this tutorial or hated it, please let me know. I am always interested in getting feedback and am looking to improve any tutorials I write. Hopefully you enjoyed this and authentication is now a lot easier for you. 34 Responses to “Tutorial: Authlogic Basic Setup”Leave a Reply |
SearchCategories |
Thank you for this tutorial, authlogic looks like a breath of fresh air in rails authentication. I think I am definitely going to try using it on my next project but I usually need some sort of role based authentication for most of my projects. Is there any chance you could cover role integration or how to setup a basic admin user type in a separate tutorial? Maybe I missed something in the documentation?
okr, roles are really a permissions system that is separate from authentication. The problem with roles is that it depends on the app. Some apps might need very granular roles, others might need some more broad / simple. There are a lot of solutions on this and I view this as a completely separate project. Lastly, depending on the type of role system you need the implementation is different. So lumping this in with Authlogic doesn’t really make sense. I have both of the rails recipes books, and one of the has a great tutorial on this. You should check it out.
Secondly, setting up a basic admin area is easy. Check out this screencast: http://www.vimeo.com/637894 . I think that is a great tutorial on how to set up an admin area using the REST development style. The screen cast uses resource_controller. You don’t have to use this, but it does help DRY up those repetitive admin controllers.
Hope this helps.
okr, you might also want to check out: http://railscasts.com/episodes/19-where-administration-goes
Step 4 comes before step 3? lol
Yes, you also need to do the first step last. (I fixed the typo)
Any chance for a tutorial on how to migrate from Restful Authentication to Auth logic?
Has anyone interfaced this with DocSavage’s rails-authorization-plugin? Cursorily, it looks like they’ll play nice together, but I’d love some verification before I go ahead and try it for myself. :-)
FTR, I prefered “authgasm”.
Vince, I have that in my queue of articles to write. I recently converted 3 of my apps from restful_authentication to Authlogic, and it was pretty simple. Mainly removing a lot of code.
Tim, I like Authgasm too, but the suits dont. I have not played around with the rails-authorization-plugin enough to answer this question properly. If you decide to mess around with it, let me know how it goes.
I just wanted to say in one day I got authlogic working with a namespaced admin area and some simple roles I built in and it works like a charm. Thank you for making such an easy to use authorization system. Now I just need to get my “forgot password” action working.
Thank for this plugin, awesome solution for a simple login.
I’ll use it as a base on my future Twitter Mashup.
Thank you very much.
Authologic will be nice when I get more built in features like below.
http://github.com/ariejan/baseapp/tree/master looks promising to me. It has all features (open id, roles, user administration, restful auth etc.) built in. Plus some template features.
I just did a personal review of 8 or 9 starter apps as well as a summary of the gems and plugins currently on display at the Rails Rumble 2008 site. I am so happy to find authlogic. Here are the pieces I think I am going to pull from these projects:
authentication layer – authlogic configatron, roles, user adminstration and profile editing, forgot password – baseapp multiple openid identities (and idselector.com ui) – embark send user his lost (decrptyed) password – insoshi quick and dirty forms – awesome_fields and better_partials
If I get it where I want it today, I’ll put it into github.
Thank you very much for this plugin. Also iam totally fresh to Ruby and Ruby on Rails it is very easy to use and (thanks to your blog here) i understand whats going on ;-)
This looks great. I haven’t been able to install yet as I get an error:
ERROR: Error installing authlogic: echoe requires RubyGems version >= 1.2
I finally found this and it seemed to work.
script/plugin install git://github.com/binarylogic/authlogic.git
Yeah, rails gem support requires echoe. I will more than likely either switch to Hoe or require echoe as a dependency.
Hey Ben,
Thanks so much for your efforts. Just came across this today on the recommendation from a friend last night. I was going through this tutorial and noticed that your user model spec in this tutorial isn’t complete. You’re missing the persistence_token. Might want to sync that up with your README in the gem.
Thanks again.
Thanks for this. I’m very new to Rails and I’m going to be using this for my first app. So far it seems simpler and easier than restful_authentication. One thing I’d like to point out is that the views in your sample app on github don’t work with the code here in this tutorial. E.g. _form.html.erb takes openid information and an email address, when that isn’t in the model created in this tutorial.
Hey Michael, thanks for the heads up on this, I changed it. But it really doesn’t matter, you could call the field that and authlogic will adjust accordingly and work just fine. It does some “smart checking” for common field names.
Akahn, yeah I had a feeling that might be a problem. I will put some notes in the views. It should be fairly obvious that there is OpenID support in the app. Simply removing the OpenID code would make the app work just fine.
Hello Ben,
great jog with Authlogic.
I was testing the plugin and it seems to work perfectly using this tutorial, but when I tried using it inside a namespace like Security::User and Security::UserSession, I had the following error:
undefined local variable or method `user’ for Security::UserSession:Class
The stack trace sent me to:
vendor/plugins/authlogic/lib/authlogic/session/base.rb:359:in `create_configurable_methods!’
So I took a look there and found this line
alias_method :#{klass_name.underscore}, :record
I figured out the problem might be the klass_name.underscore, so I tried changing it to:
alias_method :#{klass_name.underscore.tr(’/’,’_‘)}, :record
And it worked.
I was wondering if I should create a ticket at lighthouse, because it seems a little bug.
Excellent plugin! Just went through the tutorial and imho it’s nicer than anything else out there at the moment.
That said, just starting out with Rspec I’m having trouble writing specs for the users controller and controllers that require authentication.
If anyone could share some examples I’d appreciate it.
I’ve made some progress on writing specs and forked the example app on Github for anyone interested and to hopefully receive some feedback.
http://github.com/jxl/authlogic_example/tree/rspec
If you see anything that’s just plain wrong or could be improved please fork or leave a comment.
Hi, Ben:
Your plugin looked interesting enough for me to rip out restful_authentication and give it a try. But I want to repeat Tim S’s question because (unless I made a mistake, which is possible) it doesn’t seem to work out of the box with rails-authorization-plugin. That’s a very popular plugin, so it would be great if they worked together without custom code.
http://github.com/DocSavage/rails-authorization-plugin/tree/master says, “make sure your application provides a current_user method or something that returns the current user object (resful_authentication provides this out of the box).”
Authlogic does provide a current_user method, but the authorization plugin can’t seem to use it. It keeps giving me the following error message:
Authorization::CannotObtainUserObject (Couldn’t find #current_user or @user, and nothing appropriate found in hash): /vendor/plugins/rails-authorization-plugin/lib/authorization.rb:117:in `get_user’ /vendor/plugins/rails-authorization-plugin/lib/authorization.rb:74:in `has_permission?’
Did I misconfigure Authlogic? If not, what would be your official recommendation for getting these two plugins to talk with each other? I don’t want to put in my own hack and then get screwed up later when Authlogic changes.
Thanks!
James Lavin
Is there a way to do email confirmations for new accounts? (I know I can add it, just wondering if it’s builtin and/or documented somewhere?)
Also any anti-bot technologies like CAPTIAs?
Looks great!
thanks
Sort of annoyed. It took me an hour to find out I needed to install Git.
Could you point things out to noobies like me in the future? Would take two lines of text.
Thanks.
I ran across a reference to this on the RSpec mailing list and am giving it a tryout. On first blush I am favourably impressed with the entire approach, taking the application coding out of the hands of generators while providing the background functionality necessary.
The references to the view code present in the git repository may cause recent users of this tutorial some difficulty however. That code is now polluted with the changes introduced in the later tutorials OpenID and ResttingPasswords. If you do not wish to reproduce the original view code in line in this article then perhaps a different resource reference with the pristine versions might be provided instead?
Hi everyone, I apologize for taking a few days for a response, this has been an unusually busy week for me. Anyways, here are my replies:
Carlos, great find, I went ahead and fixed this, just update your gem.
James Lavin, the current_user method is just a method you create yourself. Maybe you forgot to do helper_method :current_user? Anyways, I’ll install the authorization plugin and see what the deal is. Regardless, it should work because the current_user method is no different than the restful_auth one in terms of the value it returns.
Joel, that’s really up to you. Authlogic doesn’t have this built in, but if gives you some helpful tools. Take a look at the resetting password tutorial. You can use the same things I use in there to confirm accounts, such as the perishable_token, etc.
David, I will add that in, I didn’t really think about mentioning it since the plugin url begins with git://, but I’ll put something in here mentioning git is required.
James Byrne, I will more than likely just create a branch for each tutorial and clean up the code respectively.
This seems to be a great plugin/gem. But beware of a return statement in the block after the ”@user_session.save”. I wanted to do a simple “render :text => ‘success’ and return” as a temporary workaround but this skips the after_save filter(s) and thus persisting the session. Another issue is the ability to use authlogic in cocumber tests. I’m unable to stay logged in during a scenario.
why not use
def current_user @current_user ||= current_user_session && current_user_session.user end
instead of
return @current_user if defined?(@current_user) @current_user = current_user_session && current_user_session.user
and alike for current_user_session
me again in documentation there is login_field_validates_confirmation_of_options instead of password_field_validates_confirmation_of_options
Thanks jan, I will look into that.
Ivan, because if a current user is not found it will return nil, which means it will keep executing that code. You only want that statement executed once.
Hi, my problem is that I don’t want the user to be automatically logged-in. When a user is created I can see that the cookies are set. How do i prevent it?
Nevermind my comment. Found out about session_ids => []
First off, I’ve been playing around with authlogic and I really like it so far. I appreciate your work Ben.
One question though…say I want to load that flash message with user details (say, login, last_login_at, and last_login_ip) on successful creation of a user_session. At what point do I have access to “current_user”? Can I simply call current_user.last_login_at inside the create method of UserSessionsController to build my flash message text? Thanks for any suggestions.
Lee, I don’t see any reason why you wouldn’t be able to. Try it out, keep in mind you are in control of the current_user method, so if it doesnt work because of caching (that first line: return @current_user if defined?(@current_user)), try clearing out the @current_user variable so it will try and find the user again. But I don’t see any reason why it wouldn’t work without doing this.