I’m tired of spending loads of time creating user authentication systems with permissions or swimming against the current to customize what’s available. There’s great open source stuff out there but until now, I haven’t gotten the full package with really easy customization.

The Devise and CanCan combo for user authentication and permissions in Rails is my combo of choice.

With Devise and CanCan, you can create a customized authentication and registration process in 15 minutes, and spend another 15 minutes implementing roles and permissions.

It’s pure beauty.

Note that the code here uses Rails 3. The difference in Rails 3 and Rails 2 code for this purpose should be minimal, but please refer to the documentation for differences.

Devise

Step 1 – Installation

Step 2 – Configuration

Configuration is super easy with Devise. Just choose which of the 11 available modules you would like to include in your authentic model (most up-to-date list here):

Database Authenticatable: encrypts and stores a password in the database to validate the authenticity of an user while signing in. The authentication can be done both through POST requests or HTTP Basic Authentication.

Token Authenticatable: signs in an user based on an authentication token (also known as “single access token”). The token can be given both through query string or HTTP Basic Authentication.

Step 3 – Use It!

This simple modular approach to authentication is hot. Devise also makes it really easy for you to customize views. The out-of-the-box views are great for prototyping, but if you need more, just generate the views and edit them:

$ rails generate devise:views

Devise will generate all of the views it is using and place them in an app/views/devise directory. Now you have complete control over your views.

The next thing you might want to do is customize your controllers. This is a bit more tricky with devise and we’ll get to that in a minute. Right now I want to touch on permissions and then I’ll tie it all together.

Let’s consider an example where your website is in Alpha/Beta or maybe an internal tool. You want to restrict user registration to only an administrator. Enter CanCan created by Ryan Bates.

CanCan

CanCan is a great gem for implementing model permissions. The main reasons I chose CanCan are:

The code written to check permissions is very readable

The code written to declare permissions is very concise and readable

It keeps permission logic in a single location so it is not duplicated across controllers, views, etc.

Ryan Bates has a great screen cast on using CanCan here, but I do not recommend using his roles mask method (mentioned in the screen cast). It certainly works but it’s bad database design and you will feel the pain later.

After you install CanCan (instructions here), I recommend you set up a typical users HABTM roles relationship. So you end up with migrations that look like this:

Most of this is application specific but you can see some conveniences right away. For example, the super admin role “can manage all”. That line is saying “If the user has the super_admin role, he may perform any action on any model.” Easy enough. Also notice that the product team can “read” products and assets. This means that they can access the index or show action of either of those models. You can pass a block to the can method for more complicated permission checks, but that is beyond the scope of this post and pretty easy to figure out.

Let’s take a look at the role method. I store role names as CamelCase strings in the database but I access them with underscores which is more ruby like. The method looks like this:

defrole?(role)return!!self.roles.find_by_name(role.to_s.camelize)end

Tying it all together

Now let’s go back to the situation I mentioned earlier – you want to protect user registrations. This requires us to use CanCan to check for permissions but customize the Devise Registrations controller to restrict access.

One way to do this is to copy the devise controllers into your controllers directory and start customizing. That may be the best way to go and it’s certainly an obvious path, but all I want to do restrict registration. Should I really have to re-implement the registrations controller to do that? For now, I will not. It might make sense when there are more customizations. Instead I inherit from the Devise Registrations controller. Here are the steps:

The check permissions method is really simple. It calls the CanCan method, authorize!, and checks if the current user can create users. We use resource here because devise uses resource to refer to the model that can be authenticated. Also notice how I removed the require_no_authentication filter, a Devise filter which allows access to actions without authentication.

Step 3 – Tell your routes to go to the new controller

Step 4 – Handle the CanCan::AccessDenied exception

At this point if you hit the users/sign_up page when not logged in, you will notice that a CanCan::AccessDenied is thrown. This exception is thrown anytime permission is denied so you should customize it to your liking. I put the handler in my ApplicationController:

I realize I skipped some steps in here but this post + Devise documentation + CanCan documentation should help you set up authentication with roles and permissions very quickly. Let me know if you have any questions. Enjoy!