Authentication in Rails with Netbeans6.0

Authentication of the user is the minimum step required to prevent unauthorized people from accessing applications. A lot of third party plug-ins are available for Rails for authentication.. For a simple application, like ours, the plug-ins are not necessary and filters in Rails will serve the purpose. What is a filter? It is a software component or a method, which intercepts a request for a resource in a web application and does necessary pre-processing before forwarding the request to the controller. It can also post-process a response from controller before forwarding it to the browser. In Java, Filter is a servlet with some extra-functionality and has to implement Filter Interface and methods in them. In Rails any method, which is used as a filter, becomes a filter. We will see how a method can be used as a before-filter to intercept a request and allow only authenticated users to access the controller that processes the request and re-direct others to a login page. We will create three controllers –book, user and login in our project. Only persons registered with user controller will be allowed to access the books controller and actions in it and others will be asked to login. You can refer to the earlier articles in DeveloperIQ  for the detailed steps to create a Rails project with NetBeans6.0.. Go to File->New Project. Choose  Ruby from Categories and Ruby On Rails Application from Projects and click Next and in the Wizard that follows, fill up the various parameters. Give Project Name, as bookstore and click Finish .You can see in the Project window, necessary directory structure .If you look at the file database.yml in the Configuration directory it will read as under:

development:
      adapter: mysql
      database:    bookstore_development
      username: root
      password:
      host: localhost

Go to HeidiSQL and create a database bookstore_development in MySQL . Come back to NetBeans and in the Project window Right click on the project bookstore and choose Generate -> model.You will get a wizard. Fill up the same as in Figure-1

You can see the Arguments box in the wizard was filled up with Model name and attributes and their types as follows: Book title:string author:string publisher:string price:integer

You can right click on bookstore and choose Migrate Database-> Version 1 – CreateBooks.
After the migration is over, you can once again Right click and choose Generate->scaffold  and fill up the wizard as in Figure 2

Open the routes.rb in the Configuration folder and add the line
map.connect '', :controller=>'book'
With the above steps and practically no code from us we have created a web project with Rails and NetBeans and we can run it by pressing  F6. The WeBrick server will be started in Port 3000 .Go to your Browser and in the Navigation Bar give the address as http://localhost:3000/book you will get Figure -3

Click the link New book and make a few entries .Now have some data also .

Create one more resource User as shown in Figure 4.The steps we use for creating this resource are more in tune with the Rest paradigm Rails2 is stressing .Right clicking on bookstore now choose Generate ->scafolld_resource and fill up the wizard as in Figure 4

Right clicking on bookstore once again choose Migrate Database To Version 2 –CreateUsers. Now you can access http://localhost:3000/usersNote the difference when we follow this method. The mapping Map.resources :users was added in the routes.rb by the framework itself. Ensure whether the map added earlier for book controller in the routes.rb is there Add a few users.

We will proceed to see the steps necessary for restricting access to the book resource only to users in Users resource.
. Open the file /Controllers/application.rb and modify it and the modified file should read as under:

class ApplicationController < ActionController::Base
      private

 

  def authorize session['initial_uri'] = request.request_uri unless User.find_by_id(session[:user_id]) flash[:notice] = "Please log in" redirect_to(:controller => "login", :action => "login") end end end

The method authorize defined in ApplicationController is available for all controllers in the application and we will use it as a before_filter for our BooksController. Open the file /Controllers/books_controller.rb and add the line before_filter :authorize at the beginning .Now when one invokes any action in the BooksController, the request will be intercepted by the  filter authorize. The filter first saves the uri for which the request came in session map under the key ‘initial_uri’ for later use. Then it gets the user object from the database by id and compares it to the user id in session. Before the user logs in there will be no user id in session. So the message “Please Login in” will be displayed. Rails  has a convenient way of dealing with errors and error reporting. It defines a structure called ?ash. A ?ash is a bucket (actually closer to a Hash) in which you can store stuff as you process a request. The contents of the ?ash are available to the next request in this session before being deleted automatically. You know when you use re-direct, control is passed back to the browser with the message to invoke login action in login controller . Right Click choose Generate -> Controller and in the wizard give the name of the controller and Views as login as shown in Figure 5 and click Ok.

Figure-5
                                                                                                                                              
The LoginController should read as under:

class LoginController < ApplicationController
      before_filter    :authorize, :except => :login 

 

layout "admin"               --------------------------------------------(1)

def login session[:user_id] = nil if request.post? user = User.authenticate(params[:username], params[:password])----(2) if user session[:user_id] = user.id redirect_to session['initial_uri']  --------------------------(3) else flash[:notice] = "Invalid user/password combination,if new user,click Adduser"
end end end #END:login
def logout reset_session redirect_to :controller => "login", :action => "login" end end

  1. we are using layout file admin.rhtml in /view/layouts folder instead of using the default layout file generated by Rails since we require a more advanced features as page shown in Figure 6 indicates. The figure is display of login.rhtml superimposed on admin.rhtml.. (2) in the login method we are invoking the class method authenticate in the model class user with the parameters username and password and the method returns a user object if both the parameters match with the  user found in the table user 3) if there is a user object, the request is redirected to the intial uri earlier saved in session, after saving the user id in session. Other wise the user is informed of the problem and, in case he is a new user, he is requested to click the New User link in the page displayed.

The login.rhtml should read as under:

<div class="depot-form">
      <fieldset>
      <legend>Please Log In</legend>

 

    <% form_tag do %> <p> <label for="name">Name:</label> <%= text_field_tag :username, params[:username] %> </p>

<p> <label for="password">Password:</label> <%= text_field_tag :password, params[:password] %> </p>

<p>
<%= submit_tag "Login" %> </p> <% end %> </fieldset> </div>

Select /view/layouts folder and Right Click and choose New->RHTML and get the wizard as in Figure 7 and give the File Name as admin.rhtml and click Finish.

The file admin.rhtml should read as under:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0    Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>Administer the Bookstore</title>
<%= stylesheet_link_tag "scaffold", "depot", :media => "all" %>-----------(1)
</head> <body id="admin"> <div id="banner"> <img src="/images/rtr.jpeg"/> <%= @page_title || "Ramasamy Bookshelf" %> </div>
<div id="columns"> <div id="side"> <p> <%= link_to "Books",   :controller => 'book', :action => 'list' %>  --------(2)
</p>

 


<p> <%= link_to "New user",   :controller => 'users', :action => 'create' %>
</p>

      <p> <%= link_to "Logout",     :controller => 'login', :action => 'logout' %>
</p> </div> <div id="main"> <% if flash[:notice] -%> <div id="notice"><%= flash[:notice] %></div> <% end -%>
<%= yield :layout %>  -----------------------------------------------(3)
</div> </div> </body> </html>

You can see the code is  mostly html interspersed with Ruby instructions.(1) stylesheet_link_tag helper asks the program to link the CSS files scaffold and depot. You can copy these files from the public folder from the Rails sample application available in NetBeans to the public folder of your project  (2) link_to helper specifies the controller and the action,which will be invoked if the link is clicked .(3)The keyword yield specifies the place wherein the result of the execution of code of login.rhtml should appear.

Figure 8 shows what will happen if you don’t enter password correctly. Figure 9 shows the result of successful login. Figure 10 shows the result when you access users resource.

One may say security is compromised since we store password in plain text.. Rails uses SHA1 digest which will convert a plain text password fed into it to a 160 bit hash. This can be made more secure by availing a facility called “salt’. Those who want to know about these can refer to “Agile web Development with Rails” by Dave Thomas Chapter 11 .








}