Creating a Login System in Rails
by Saurabh Bhatia
November 17, 2009
|
Building the next community driven powerhouse using Ruby on Rails? Let Saurabh show you how easy it is to create a login system for your Rails project, to encrypt your passwords and start and destroy session. A good way to provide access levels in your Rails applications.
|
Introduction
Continuing to build our Ruby on Rails driven site, our
Employee Information System has been created. Now we just
don't want anyone to come and access it. We would like to
add levels of abstraction which means only the privileged
users can come and see the database, once they login to the
system.
Now what should be the flow of the system

Figure 1
As the user comes to the Landing Page, he is presented
with a Login Form. The fields are Username, Password and Go.
If the user enters a correct set of credentials, he is taken
to the employee index page where the list of employees is
displayed and the user can add a new set of employees.
Let's start by first adding a table in the database. Let'
s name it, users table as it holds all the records of System
Users. We create a Model for this so that we have the tables
and we can write some logic for our users.
saurabh@home:/media/S3A6128D005/Users/ongc/eim$ ruby script/generate model user
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/user.rb
create test/unit/user_test.rb
create test/fixtures/users.yml
exists db/migrate
create db/migrate/20091116113942_create_users.rb
Edit the migration file to add table details to it:
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.column :username, :string
t.column :password, :string, :limit => 40
t.column :salt, :string, :limit => 40
t.timestamps
end
end
def self.down
drop_table :users
end
end
We will encrypt our password before storing into the
database as a measure of security. To do our encryption we
will use the rub digest library which creates a an MD5
encrypted password and a salt, which works as a key to
decrypt the password.
saurabh@home:/media/S3A6128D005/Users/ongc/eim$ rake db:migrate
(in /media/S3A6128D005/Users/ongc/eim)
== CreateUsers: migrating =====================================
-- create_table(:users)
-> 0.0856s
== CreateUsers: migrated (0.0858s) ============================
In our model, we add validations to check if the username
is unique or not and whether the password is present or not.
The encrypt password method in the model generates an MD5
encryption and password matching
require "digest"
class User < ActiveRecord::Base
validates_uniqueness_of :user
validates_presence_of :user, :password
def encrypt_password
if (self.salt == nil)
self.salt = salt_generator(5)
self.password = Digest::MD5.hexdigest(self.salt + self.password)
else
self.password = Digest::MD5.hexdigest(salt + self.password)
end
end
def password_matches?(password_to_match)
self.password == Digest::MD5.hexdigest(self.salt + password_to_match)
end
private
def salt_generator(len)
numbers = ("0".."9").to_a
newrand = ""
1.upto(len) { |i| newrand << numbers[rand(numbers.size - 1)] }
return newrand
end
end
Now, we start creating the controller to add the login
and logout actions to it. We will also add an access level
such that login is made compulsory to the system for
entering any employee record.
def login
if request.post? and params[:user]
@User = User.new(params[:user])
user = User.find_by_username(@User.username)
if user and user.password_matches?(@User.password)
session[:id] = user.id
redirect_to :action => 'index'
else
flash[:notice] = "Invalid Username or Password!"
end
end
end
def logout
if session[:id]
reset_session
redirect_to :action => 'login'
end
end
In this method, the Login action calls the user details
using the parameter username, it matches the username and
password with the entered credentials; starts the session
with a user id being carried in it and redirects the action
to index. Logout action calls the session id and calls
reset_session method, which destroys a session.
Once, we have finished creating a login and logout we
need to make it a compulsion to login before a user can
access an employee's details. The before_filter directive
helps to put to force this rule onto all the people who
access the system.
before_filter :login_required, :except => [:login, :logout]
private
def login_required
if !session[:id]
redirect_to "/admin/login"
return false
end
end
With controller, Model and the database ready, we can now
go ahead and create our Login Page view, login.htmlerb.
<% form_for :user, @user do |f| %>
<%= error_messages_for :user %>
Username: <%= f.text_field :username %><br/>
Password: <%= f.password_field :password %><br/>
<%= submit_tag "Go" %>
<% end %>
Our login system is now ready to use.
Plugin Methods to Implement Login in Rails
Now a days there are a lot of plugins available which
saves a lot of time and effort. Below you'll find some more
of the popular ones thatwork with Ruby on Rails.
- Restful Authentication: Previously known as
acts_as_authenticated, Restful authenticated is a full blown
login system plugin which generates the signup flow along
with login, the restful way. It also contains a system for
activation email and key. It can be downloaded at http://github.com/technoweenie/restful-
authentication.
- Authlogic: Another very popular and clean implementation
of Rails based Login system is Authlogic. It generates the
users and sessions for the application and simply resides
inside the vendors/plugins folder. It can be downloaded at
http://
github.com/binarylogic/authlogic.
- Muck-Users: Muck and autlogic gem based system, which
generates, Login, Sessions and User Creation Logic. It can
be used by downloading from http://
github.com/binarylogic/authlogic.
Conclusion
Rails provides multiple methods of encryption like sha1
and MD5 internally as a part of the Rails framework.
However, the plugins provide a fairly simple and
straightforward methods to implement login, sessions and
sign up flow.
|