DivineRails

Ruby on Rails

Blog

Authentication and Authorization in Rails Using Devise and CanCan

Posted by Rq Bukhari on April 29, 2012 at 5:30 AM



Are you tired of spending lot of time creating user authentication systems. Are you tired of creating a system to manage different roles of users. There are many useful open source stuff available. Devise and CanCan are my choice for user authentication and authorization.


Devise and CanCan are customizable and easy to use. You don't need to spend lot of time on user authentication and authorization. Here in this post I'm going to explain how to use Devise and CanCan in rails 3.


Devise

 


Installation


Open your gemfile and include these two gems.


   gem 'devise'

   gem 'cancan'


Now install these gems using the "bundle install" command. After the successful installation of gems we have to generate the installation of devise using the commands below


   rails generate devise:install

   rails generate devise user


 

 

Configuration

 


The second command will generate user model and migration. You can include any extra fields you want to include in the migration. It also includes the following modules:


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.

Oauthable:

                  Adds OAuth2 support

Confirmable:

                  Sends emails with confirmation instructions and verifies whether an account is already confirmed during sign in.

Recoverable:

                  Resets the user password and sends reset instructions.

Registerable:

                  Handles signing up users through a registration process, also allowing them to edit and destroy their account.

Rememberable:

                  Manages generating and clearing a token for remembering the user from a saved cookie.

Trackable:

                  Tracks sign in count, timestamps and IP address.

Timeoutable:

                  Expires sessions that have no activity in a specified period of time.

Validatable:

                  Provides validations of email and password. It’s optional and can be customized, so you’re able to define your own validations.

Lockable:

                  Locks an account after a specified number of failed sign-in attempts. Can unlock via email or after a specified time period.


You can choose any of them and can configure devise accordingly. Here I show how to choose.

 


# In your model class

User < ActiveRecord::Base

                  devise :database_authenticatable, :confirmable, :recoverable, :rememberable, :trackable, :validatable


If you want to add a new attribute for user you can also add it easily just include it in the attr_accessible like if you want to add username for user:


                  attr_accessible :username, :email, :password, :password_confir...

 


Including the username in attr_accessible you will also have to include it in migration.

 


# In your migration

 

 create_table :users do |t|

                  t.string :username

                  t.database_authenticatable

                  t.confirmable

                  t.recoverable

                  t.rememberable

                  t.trackable

                  t.timestamps

end 

 

 


# In your routes


                  devise_for :users

 

 


Now run the "rake db:migrate" command to run this new migration and create a user table in database.

 


Use Devise


When devise is configured successfully you can use it by including the before_filter in your controller.

 

# In your controllers


                  before_filter :authenticate_user!


#if you want to skip authenticate_user for some action you can configure like


                  before_filter :authenticate_user!, :except => [:some_action_without_auth]

 


You can access the logged in user details by using current_user.


def index

                  @anything = current_user.anythings

end

 

 


We can also customize the views generated by devise, We just need to generate the views and customize it according to our application.

To generate views simple run the following command:


                  rails generate devise:views

 

Now Coming to the authorization of the application. Suppose we have multiple roles in our application. We have to handle these multiple roles like admin, pro-user, basic-user etc. CanCan provide us this functionality and makes it easy for us to configure it in less time.



 

 

CanCan

 

 

Installation


Installation of cancan is already performed in our application because we included both devise and cancan in our gemfile and installed the gems. I like cancan because of the following reasons:

 

 


>   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.

>   Aliasing actions (read = index and show) creates more concise and readable code.


 

 

After the installation of cancan you need to set up a typical users HABTM roles relationship. This is not necessary to create a HABTM roles relationship but it makes the use of cancan so easy. The migrations will look like this:


class CreateRoles < ActiveRecord::Migration

                  def self.up

                                    create_table :roles do |t|

                                                      t.string :name

                                                      t.timestamps

                                    end

                  end 

                  def self.down

                                    drop_table :roles

                  end

end 

class UsersHaveAndBelongToManyRoles < ActiveRecord::Migration

                  def self.up

                                    create_table :roles_users, :id => false do |t|

                                                      t.references :role, :user

                                    end

                  end

 

                  def self.down

                                    drop_table :roles_users

                  end

end

 

 


Add the following in your models:


# User Model

class User < ActiveRecord::Base

                  has_and_belongs_to_many :roles

 

 


# Role model

class Role < ActiveRecord::Base

                  has_and_belongs_to_many :users


 

 

Now run "rake db:migrate" and the tables will be created. The next step to configure and use cancan is to create ability class. In this class you will authorize user. You will explain the privileges of different roles. The ability class will look like below:

 

class Ability

                  include CanCan::Ability 

                  def initialize(user)

                                    user ||= User.new # guest user 

                                    if user.role? :super_admin

                                                      can :manage, :all #This shows that the super_admin can manage everything

 

                                    elsif user.role? :product_admin

                                                      can :manage, [Product, Asset, Issue] # Show that the product_admin can manage products and its related other things.

 

                                    elsif user.role? :product_team

                                                      can :read, [Product, Asset]  # manage products, assets he owns

                                                      can :manage, Product do |product|

                                                                        product.try(:owner) == user

                                                      end

                                                      can :manage, Asset do |asset|

                                                                        asset.assetable.try(:owner) == user

                                                      end

                                    end

                  end

end


 

 

It's enough for now. I'll explain some more customization of CanCan and Devise in next post. I hope there is no error in the post if any then let me know.

Thanks.

 

 

Categories: None

Post a Comment

Oops!

Oops, you forgot something.

Oops!

The words you entered did not match the given text. Please try again.

Already a member? Sign In

0 Comments