The goal of this tutorial is to give you a solid understanding of the best practices for implementing authentication and authorization in Rails. You'll learn how to securely manage user access to your application, and how to restrict access to certain parts of your app based on user roles.
You will learn:
- The difference between authentication and authorization
- How to implement authentication using sessions and cookies
- How to implement authorization using roles and permissions
Prerequisites:
- Basic knowledge of Ruby on Rails
- Familiarity with HTML and CSS
- Understanding of MVC architecture
Authentication: Authentication is the process of verifying the identity of a user, device, or system. It often involves a username and password, but can involve any method of demonstrating identity, such as a smart card, retina scan, voice recognition, or fingerprints.
Authorization: Authorization is the process of giving someone permission to do or have something. In multi-user systems, a system administrator defines for the system which users are allowed access to the system and what privileges of use.
Devise is a flexible authentication solution for Rails. It handles all of the complexity of implementing user authentication, including registration, login, and password reset.
Install Devise
gem 'devise'
After adding the gem to your Gemfile, run bundle install
to install it. Then, run rails generate devise:install
to create the necessary configuration files.
Create a User model
rails generate devise User
This will generate a User model with some Devise modules. Run rails db:migrate
to create the users table.
Pundit provides a set of helpers which guide you in leveraging regular Ruby classes and object-oriented design patterns to build a simple, robust and scalable authorization system.
Install Pundit
gem 'pundit'
After adding the gem, run bundle install
and then rails generate pundit:install
to generate the application policy.
A common approach to authorization is to assign roles to users, and permissions to roles. A user gains the permissions of the roles they have.
class User < ApplicationRecord
enum role: { guest: 0, user: 1, admin: 2 }
end
This will add convenience methods like user.admin?
which will return true if the user's role is 'admin'.
Example 1: User Registration with Devise
# app/controllers/users/registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
# POST /resource
def create
build_resource(sign_up_params)
resource.save
yield resource if block_given?
if resource.persisted?
if resource.active_for_authentication?
set_flash_message! :notice, :signed_up
sign_up(resource_name, resource)
respond_with resource, location: after_sign_up_path_for(resource)
else
set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
expire_data_after_sign_in!
respond_with resource, location: after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
set_minimum_password_length
respond_with resource
end
end
end
Example 2: User Authorization with Pundit
# app/policies/article_policy.rb
class ArticlePolicy < ApplicationPolicy
def update?
user.admin? or not record.published?
end
end
This policy allows admins to update any articles, and allows other users to update only unpublished articles.
You've learned about authentication and authorization, and how to implement them in Rails using Devise and Pundit. You also learned about using roles and permissions for authorization.
Next steps:
- Try implementing different types of user roles
- Experiment with different permissions for each role
- Learn more about Devise and Pundit
Additional resources:
- Devise Documentation
- Pundit Documentation
Exercise 1: Implement a user registration form with Devise.
Exercise 2: Create a policy with Pundit that allows only admins to delete users.
Exercise 3: Extend the User model with more roles, and create a policy for each role.
Happy coding!