[Reprinted] with complete RBAC authorization of a system of rails application (Part I)

sponsored links
http://blog.csdn.net/cheng5128/archive/2009/07/01/4613851.aspx

This is a simple RBAC authorization system. It really is simple nor easy, but the rails in the framework of world famous, all become particularly easy, of course, but also to worship as we will use the trust of the two plug-ins. BS, let us talk about our project right. This is a site similar to Wikipedia, you can say it is a simple version of what Ye Hao, its codename has been set up for the Wiki! Project requirements are also very simple, users can publish anything after registration. But this seems to not take any authorization system, so we have to put it out a little bit complicated, the way, our authorization system is well-known RBAC (Role Based Access Control, Role-based access control). Changing demand in the authorization, we only need to introduce a new role can settle them anymore. Because the role (Role) in RBAC, a certain amount of authority as the existence of the collection. In addition, as a synonym for the development of fast sensitive, rails have long provided a major hit this plug-in, so I might also be that simple.

Well, now re-examine our programs, we ask that only registered users can log in published articles, Eh-hem, here, that the formal point of it, to publish entries (lemma). Ah, here we have the first resource lemma. Of course, if more than one of these entries, it easy to get, so we have to introduce tag cloud this trendy stuff. To encourage users to create high-quality entries, or write entries, each entry we have default certain points, when the user get this after completing the entry points. Some entries may not be well written, we will increase the corresponding gold content of these entries, although this is a property of entry, but we can not allow users to edit the properties for. Harm. Also to prevent the offensive in the waste or other anti-unbearable. Fixed illegal things out on our website, we are to set up similar to the BBS of the moderator system, I call it peace maker (Order Guardian), and of course have ignored the existence of all the rules, to remove incompetent peace maker out of the management, I call providence breake (the wrong side of God's person). peace maker can change an entry points, but not for themselves or others extra points, extra points are performed automatically by the system. As a wiki, of course, a total document system, we can let the user through the steps to become someone else created a co-creator of the term, but attendance alone does not contribute to a lack of access points, and must be modified only to add points, and do not important points for bonus points, so we have to make a switch here. Undoubtedly, the entry and the user is a many to many relationships require an intermediate table between them, where we played a trick that is! Ah, generally is the way to doing the other side, rails, like java do not need to start as a big drop hit the document, so it is not developing fast Min!

Our development tool is netBeans, the environment is window XP, ruby 1.8.6, rails 2.3.2, because we will use a new feature to 2.3, so be sure to upgrade to rails2.3. So, here we go.

[Reprinted] with complete RBAC authorization of a system of rails application (Part I)


Create a new project.

[Reprinted] with complete RBAC authorization of a system of rails application (Part I)


Specified database.

[Reprinted] with complete RBAC authorization of a system of rails application (Part I)


Create the database.

Next is to install plug-in, first one is the famous restful-authentication. We need to use it for login authentication, as the ruby community recognition of the most famous discussion of railsforum.com the longest string of disputes out of the results, it is absolutely trustworthy. The second is the declarative authorization, the authorization system we basically will depends on it. What are the advantages it? Tigong from view to the controller to the model De authorization controls, a statement Shi call authorization rules to allow the authorization logic and business logic separated concentrated in a configuration file employing the DSL written authorization rules, to provide graphical interface allows you to Lishunfuza authorization system, and so on. But now let's open a command station, navigate to the project's root directory it:

ruby script/plugin install git://github.com/technoweenie/restful-authentication.git
git clone git://github.com/stffn/declarative_authorization.git vendor/plugins/declarative_authorization

Note: This need to install Git. Own google it!

Create User Module and Session module, to the point, we do not have email activated registration, automatic login and other fashion features, so the installation plug-in when prompted, simply enter:

ruby script/generate authenticated user sessions
rake db:migrate

Authorization model in RBAC, User and Session is representing the two resources are two important elements. Authorization system in general, User permissions as owner or main users exist in the RBAC authorization model, a slight change in the situation, accurate speaking, the additional body or the host authority. Permissions are moved to our Role of the body mentioned a while. Session in RBAC is a relatively obscure element. Needless to say, Session First of all, no state for us to solve Web challenges, this is mainly done by the restful-authentication. Second, we can all through the session to carry the authorized users. This is very important, as mentioned earlier, in the RBAC authorization model, User is only pure user rights have been stripped off. User can not be directly associated with the Privilege, User should have to operate on a resource, you must go through the Role Association. If the user registration, we can assign him a call user (registered user) or wikier (Wiki) such a role, but if he is not registered or not logged in, does that mean the site in a series of hurdles Sometimes, a website there are always some open source it, this not inconsistent with our original intention. So we ask even though the user does not log should give him a role, this responsibility by the declarative_authorization.

Open users_controller and sessions_controller required to include AuthenticatedSystem comment.

[Reprinted] with complete RBAC authorization of a system of rails application (Part I)


[Reprinted] with complete RBAC authorization of a system of rails application (Part I)


Modify application_controller, which, current_user, logged_in? Are from restful-authentication plug-in; for safety, we also used filter_parameter_logging approach to such sensitive fields as the password from the log filter to prevent hackers peeping into!

[Reprinted] with complete RBAC authorization of a system of rails application (Part I)


Over the next step is very important, and we add the roles to User table field, which RBAC's Role element is the distribution of units of competence and the carrier of the user (Users) and permissions (Permissions) of the agent layer, used to decouple permissions and user relations. We can also separate a module Role, User at the same time to have multiple roles, but now we are all simple, in order to reduce the database of the JOIN operation.

ruby script/generate migration AddRolesToUsers roles:text
class AddRolesToUsers < ActiveRecord::Migration
  def self.up
    add_column :users, :roles, :string,:default => "wikier"
  end

  def self.down
    remove_column :users, :roles
  end
end

Then:

rake db:migrate

User modules in the start, we still do some trivial work, which will make our future the things we look pleasing. No wrong, and that is the global template project. In app / views / layouts / directory to add application.html.erb, the specific code:

[Reprinted] with complete RBAC authorization of a system of rails application (Part I)


It uses many of the custom method, we app / helper directory New layout_help.rb, put them inside to:

module LayoutHelper
  def title(page_title, show_title = true)
    @content_for_title = page_title.to_s
    @show_title = show_title
  end

  def show_title?
    @show_title
  end

  def stylesheet(*args)
    content_for(:head) { stylesheet_link_tag(*args.map(&:to_s)) }
  end

  def javascript(*args)
    args = args.map { |arg| arg == :defaults ? arg : arg.to_s }
    content_for(:head) { javascript_include_tag(*args) }
  end
end

Modify users_controller, improve its restful function. Which use before_filter, not only to DRY, also taking into account the back of the access control. The revised code is as follows:

class UsersController < ApplicationController
  before_filter :load_user, :only => [:show, :edit, :update, :destroy]
  before_filter :new_user, :only => :new
 
  def index
    @users = User.all
  end

  def new;end

  def create
    logout_keeping_session!
    @user = User.new(params[:user])
    success = @user && @user.save
    if success && @user.errors.empty?
      self.current_user = @user # !! now logged in
      redirect_to users_url
      flash[:notice] = " The registration was successful  ."
    else
      flash[:error]  = " Registration failed  ."
      render :action => 'new'
    end
  end

  def show;end

  def edit;end

  def update
    if @user.update_attributes(params[:user])
      flash[:notice] = " Update user success  ."
      redirect_to @user
    else
      render :action => 'edit'
    end
  end


  def destroy
    @user.destroy
    flash[:notice] = " Delete user success  ."
    redirect_to users_url
  end

  protected
  def load_user
    @user = User.find params[:id]
  end

  def new_user
    @user = User.new
  end
end

Changes _user_bar.html.erb

<div>
  <% if logged_in? %>
    <%= link_to " Log off  ",logout_path, :title => "log in"  %>
    <%= link_to " Welcome to  ,"+current_user.login+"!",current_user %>
    <%= link_to " User Center  ",current_user %>
    <%= link_to " The list of users  ", users_path if controller_name != "users" %>
  <% else %>
    <%= link_to " Login  ",  login_path, :title => "log in"  %>
    <%= link_to " Registration  ", signup_path, :title => "create an account"  %>
  <% end %>
</div> 

Add users # index view

<%- title " The list of users  " -%>
<table>
  <tbody>
    <tr>
      <th> Account number  :</th>
      <th> Role  :</th>
      <th> Operation  :</th>
    </tr>
    <%- @users.each do |user| -%>
      <tr>
        <td><b><%= link_to user.login,user %></b></td>
        <td><%=  h user.roles.map(&:to_s) * ',' if user.roles %></td>
        <td>
          <%= link_to ' Edit  ', [:edit,user]  %>
          <%= link_to ' Delete  ', user, :confirm => 'Are you sure?', :method => :delete  %>
        </td>
      </tr>
    <%- end -%>
  </tbody>
</table>

Add users # show view

<% title " User Center  " %>
<table>
  <tbody>
    <tr><th> Account number  :</th><td><%=link_to @user.login ,[:edit,@user] %></td></tr>
    <tr><th> Mailbox  :</th><td><%= @user.email %></td></tr>
    <tr><th> Role  </th><td><%= h @user.roles.map(&:to_s) * ',' if @user.roles  %></td></tr>
  </tbody>
</table>
<%= link_to " Returns the  ",users_url %>

Remove the public's index.html, in routes.rb add a new routing rule.

ActionController::Routing::Routes.draw do |map|
  map.logout '/logout', :controller => 'sessions', :action => 'destroy'
  map.login '/login', :controller => 'sessions', :action => 'new'
  map.register '/register', :controller => 'users', :action => 'create'
  map.signup '/signup', :controller => 'users', :action => 'new'
  map.resources :users
  map.resource :session
  map.root :users
  map.connect ':controller/:action/:id'
  map.connect ':controller/:action/:id.:format'
end

Start rails:

ruby script/server

[Reprinted] with complete RBAC authorization of a system of rails application (Part I)


Modify users # new view

<% title " New user  " %>
<% @user.password = @user.password_confirmation = nil %>
<fieldset>
<%= error_messages_for :user %>
<% form_for @user do |f| -%>
  <p><%= f.label :login,' Account number  :' %><br/>
  <%= f.text_field :login %></p>

  <p><%= f.label :email, ' Mailbox  :' %><br/>
  <%= f.text_field :email %></p>

  <p><%= f.label :password,' Password  :' %><br/>
  <%= f.password_field :password %></p>

  <p><%= f.label :password_confirmation, ' Confirm password  :' %><br/>
  <%= f.password_field :password_confirmation %></p>

  <p><%= f.submit ' Registration  ' %></p>
<% end %>
</fieldset>

[Reprinted] with complete RBAC authorization of a system of rails application (Part I)


[Reprinted] with complete RBAC authorization of a system of rails application (Part I)


Well, let's New edit.html.erb, handling roles in this important field in it. User modules are usually the most important parts of the application, edit, delete and other operations generally only by the administrator to perform, the user can touch and even if such a sensitive area, it is generally an emasculated the editing interface. User model for example, login and password for the user login process is not allowed to modify, so we disabled in the form of this domain, the password is encrypted using the SHA1 not reverse decipher, simply do not provide changes. User model in order to protect the safety of most of the field, we also use a "white list"; this restful_authentication plug-in has been done for us, but the roles field is later added, we have hands-on corrections. In the User model attr_accessible method is the last to add the roles, namely:

attr_accessible :login, :email, :name, :password, :password_confirmation,:roles

Then add the following code in the model (super important)

 def role_symbols
    @role_symbols ||= (roles || []).map {|r| r.to_sym}
 end

New users # edit view

 <% title " Edit user  " %>
<fieldset>
  <% form_for(@user) do |f| %>
    <%= f.error_messages %>
    <p>
      <%= f.label :login," Account number  " %><br />
      <%= f.text_field :login,:disabled => true  %>
    </p>
    <p>
      <%= f.label :email," Mailbox  " %><br />
      <%= f.text_field :email %>
    </p>
    <p>
      <%= f.label :roles," Role  " %><br />
      <%= f.select :roles, [[' Wiki  ','wikier'],[' Order the guardian  ','peace_maker'],[' Disobedience of the people of God  ','providence_breaker']], {:include_blank=>" Please select the  ",:selected => 0} %>
    </p>
    <p>
      <%= f.submit " Update  " %>
    </p>
  <% end %>
</fieldset>
<%= link_to " Returns the  ",url_for(:back) %>

[Reprinted] with complete RBAC authorization of a system of rails application (Part I)


At this point nothing has been no restful authentication, and then down we can focus on the development of licensing systems.

Open environment.rb, add:

config.load_once_paths += %W( #{RAILS_ROOT}/lib )

This is used to ensure that plug-ins will not load error declarative_authorization.

Open application_controller, add

  before_filter :set_current_user
  protected
  def set_current_user
    Authorization.current_user = current_user
  end

The overall pre-filter, will restful authentication of current_user substituted into the declarative authorization method current_user of the same name. Note that both current_user are Session object, which the bulk of our User object, which ensures that we can save multiple pages in the user's information. If the restful authentication of current_user is empty, declarative authorization will create an anonymous User object, and put it in the declarative authorization of current_user. It has a role_symbols property (which is why our custom User model to add a role_symbols method), a value of guest. The guest substance is declarative authorization for the role of our pre-default, when the request is not associated with any user or when a user does not have any role to be called. This realized the relevance of the User and Role.

[Reprinted] with complete RBAC authorization of a system of rails application (Part I)


User anonymous source, located in (RAILS_ROOT) / vendor \ plugins \ declarative_authorization \ lib \ declarative_authorization \ authorization.rb inside

  # Represents a pseudo-user to facilitate guest users in applications
  class GuestUser
    attr_reader :role_symbols
    def initialize (roles = [:guest])
      @role_symbols = roles
    end
  end

Open users_controller, open the controller level of access control.

class UsersController < ApplicationController
  before_filter :load_user, :only => [:show, :edit, :update, :destroy]
  before_filter :new_user, :only => :new
  filter_access_to :all
  filter_access_to [:show, :edit, :update], :attribute_check => true
 #------
end

Here involves two terms: coarse-grained and fine-grained.

Coarse-grained: that type of level, just check the object type (Class), rather than pursue a particular instance of it.

Fine-grained: an instance of class, said that the need to consider the specific instance of the object (Instance). For example, only I can view and edit their own user information. This we have by comparing ID or a particular property can be achieved, therefore: arrtibute_check => true (to open the property inspector) is prepared for this.

More of them we can open the model-level access control, the system will rewrite the query according to your instructions authority to prevent data from being illegally manipulated.

require 'digest/sha1'

class User < ActiveRecord::Base
   using_access_control
#------
end

However, restful authentication plug-in because, when we log in, or when access to sessions # create action, restful authentication has not only changed the Session object's state is also trying to change the User Session object inside the state of the object, and we generally do not allow users A change in the logged in User object state (which is equivalent to update it!), an error.

Authorization::NotAuthorized (No matching rules found for update for #<Authorization::GuestUser:0x4c1b7c8 @role_symbols=[:guest]> (roles [:guest], privileges [:update, :manage], context :users).):
## It requires our guest role also have  update And mange privileges  , We generally only allow guest in  users Resources have read_index and  create Privileges  .
## This property to define authorization rules behind the content, then some will understand  !

Therefore, we gave up on the User model, model-level authorization control it.

In addition, view-level access control, direct link on the page block. Correspondingly, the controller-level access control is to block the address bar url, model-level access control is to deal with hackers. The first two may be caused by misuse, and finally an affirmation with ill intent. View-level access control for a while to say, because there is no good custom authorization rules, it is difficult to give you a visual effect.

In order to achieve licensing rules and business logic separation, declarative authorization specified authorization rules for all definition to a configuration file, and we provide specialized of DSL to write authorization rules. First of all, we have the \ vendor \ plugins \ declarative_authorization directory sample authorization_rules.dist.rb copied to config directory, and renamed authorization_rules.rb. Open authorization_rules.rb, remove the comments, it should look like this:

authorization do
  role :guest do
  end
end

privileges do
  privilege :manage, :includes => [:create, :read, :update, :delete]
  privilege :read, :includes => [:index, :show]
  privilege :create, :includes => :new
  privilege :update, :includes => :edit
  privilege :delete, :includes => :destroy
end

The code is divided into two blocks, block and privileges authorized by block.

Look at the privileged block, five have been given the privilege of four simple privileges (: read,: update,: create,: delete) and a composite privileges (: manage). include is the controller of the action behind the name. See next map, in rails applications, we have to operate on a resource, must be action. For some action, it is another action as a precondition. Such as the update action, must go through edit action, through the edit action rendering the view, again edit.html the form submission to reach the update action. Therefore, those four simple privileges on the construction index, show, edit, update, and destroy the five restful style of the action of the access control on the line. If not, then you can customize the action, then a visit to their control.

[Reprinted] with complete RBAC authorization of a system of rails application (Part I)


Look authorized block, which is used to assign permissions. Note that permission (Permission), not a privilege (Privilege). As we have just finished the privilege of blocks, those privileges are light on some of the resources that the controller action for access control, but does not specify a specific type of resource, here we take these privileges into rights of the . Has said that permission, then the "limit" who? Ah, it is easy to see, is restricted to a role, limited to certain resources only to specific Jiaose specific Operation on the particular resource, but also to meet certain requirements (such as controller Zhong Kai Qi property inspection, concrete way to check is defined here). One popular formula is this: permissions = resources + action. Click here to get work, where operations are encapsulated in the privilege, a privilege may have N-operation, but also attributes such conditions prosecution investigation, so if permissions = resources * privileged conditions. And a role might be able to operate a variety of resources, therefore, in a sense, the role is to set a certain number of privileges. Complete understanding of these, let us write it some authorization rules. By default, has a guest role we assign. It will request and are not associated with any user or when a user does not have any role to be called. Therefore, if our application has some public page, you can use the guest to let those who have not logged on user to achieve access. Now our application is also very small, only two resources (User and Session). To allow users to freely log, we should not set the Session authorized control. User resources, we intend to allow anyone to access index, show and edit only the user can access to - which of course are required to log into wikier, the basic requirements can not be property inspections to determine whether the same person!

authorization do
  role :guest do
    has_permission_on :users, :to => [:read_index,:create]
  end

  role :wikier do
    includes :guest
    has_permission_on :users, :to => [:read_show,:update] do
      if_attribute :id => is {user.id}
    end
  end

  role :providence_breaker do
    has_permission_on :users, :to => :manage
  end
end

privileges do
  privilege :manage, :includes => [:create, :read, :update, :delete]
  privilege :read, :includes => [:index, :show]
  privilege :read_index, :includes => :index
  privilege :read_show, :includes => :show
  privilege :create, :includes => :new
  privilege :update, :includes => :edit
  privilege :delete, :includes => :destroy
end

Restart our application Wiki, after all modified environment.rb. When we do not log on, test its authority control.

[Reprinted] with complete RBAC authorization of a system of rails application (Part I)


According to authorization rules, we do not log on, we have been given the role of guest can access users # index, followed by clicking the link above five (red circle up). Found to be able to log on and register, the bottom three were presented with a white page: "You are not allowed to access this action."

[Reprinted] with complete RBAC authorization of a system of rails application (Part I)


Not have sufficient permissions to access the result in failure.

[Reprinted] with complete RBAC authorization of a system of rails application (Part I)


If you are dissatisfied with this in English, you can add in the current controller of a protected action

class UsersController < ApplicationController  
#----------  
protected  
  
def permission_denied  
    respond_to do |format|  
      flash[:error] = ' Sorry, you do not have sufficient privileges to access this page  !'  
      format.html { redirect_to request.referer }  
      format.xml  { head :unauthorized }  
      format.js   { head :unauthorized }  
    end  
  end  
#----------  
end  

When we registered, immediately became Wiki (wiki). Wiki has tourists all rights (includes: guest). Ah, I think, is the time to explain what the rules mean that authorization. declarative authorization plug-in provides a powerful DSL order, so that the code is very easy to interpret. For example:

has_permission_on :users, :to => [:read_index,:create]

Combination of the above privileges = privileges if the conditions of resources * formula, the role of this permission to users in the unrestricted use of resources: read_index with: create the privilege, then humanity, let the role of the freedom to access users # index (the view and the corresponding action ) and the users # new (view with the corresponding action) and the users # create (only action). Note, in order to segment the coarse-grained permissions, we added two new privileges: read_index with: read_show.

includes :guest

Said earlier, inherited the role: guest of all rights.

 has_permission_on :users, :to => [:read_show,:update] do
      if_attribute :id => is {user.id}
 end

Id must meet the same two conditions, in order to access users # show and users # edit and users # update. if_attribute: id of the id, you want to access the resources id, specific to this case is users_controller removed prior to use before_filter that @ user. And (user.id) in the user always is current_user, we log on before the plug is allocated to our anonymous User object, or log in to our own User object.

When our role as a wiki, the original can not visit the two places (users # show and users # index) can have access to it! But for visitors, this is a very depressing thing - "can not and should not be the place to visit to let me see Well, let me click into disappointing to see such a thing!" So we have to use to view level access control, leaving people without the appropriate permissions can not see them, even view the source code can not see.

[Reprinted] with complete RBAC authorization of a system of rails application (Part I)


[Reprinted] with complete RBAC authorization of a system of rails application (Part I)


This is the tourists to see the page.

[Reprinted] with complete RBAC authorization of a system of rails application (Part I)


This is a wiki (regular users) to see the page.

[Reprinted] with complete RBAC authorization of a system of rails application (Part I)


This is the administrator to see the page.

This point, a complete authorization system is complete, the plug-in for more advanced applications will be introduced in the next section.

CSS Annex: I download!
  • del.icio.us
  • StumbleUpon
  • Digg
  • TwitThis
  • Mixx
  • Technorati
  • Facebook
  • NewsVine
  • Reddit
  • Google
  • LinkedIn
  • YahooMyWeb

Related Posts of [Reprinted] with complete RBAC authorization of a system of rails application (Part I)

  • ruby in the literal statement

    JS remember to do often use the literal approach to a statement variable, especially in the circle inside the RUBY to do after the practice has been adopted for this habit. Today, a space to test The results are as follows: user system total real Arr ...

  • For the past two days, ruby development web site performance test summary

    This is only the individual test, is also a ruby beginner test, if ill-Optimize and causing significant error also invited Members to make the exhibitions. Rails vs Rack vs Merb: Merb worse performance than Rails, but documents, rich plug-ins, plus Rack c

  • js events Guinness 2

    Event source object event.srcElement.tagName event.srcElement.type Capture release event.srcElement.setCapture (); event.srcElement.releaseCapture (); Events button event.keyCode event.shiftKey event.altKey event.ctrlKey Return value events event.returnVa

  • struts2 ajax verify the existence of input values

    struts2 ajax verify the existence of input values Today to do the struts2 ajax validate input regarding the existence of the function, and now share with everyone, I hope everyone many opinions!!! input.jsp page code: <html> <body> <s: ...

  • Eclipse to run using the specified JVM m2eclipse plugin can not find tools.jar

    Used the m2eclipse plug-ins using struts2 when com.sun necessary to rely on the default-tools.jar, specifically because at the struts-annotations bag designated default-tools.jar <profile> <id> default-tools.jar </ id> <activatio ...

  • hibernate in the get method and the difference between load method

    hibernate in the get method and the load method of the fundamental difference is: If you use the load method, hibernate consider the corresponding object id (database records) are in the database must exist, so it can be assured that the use, it can be as

  • Struts + Spring + Hibernate practice

    Tools: Eclipse3.1, MyEclipse4.03, Tomcat5.5.9, Properties Editor plug-ins, MySql4.1.13 New construction: the name for the login Create Struts framework Create index.jsp, add a link to login.jsp Press Ctrl + N, to create login.jsp, LoginAction, the use of

  • jBPM Development Getting Started Guide

    Although the workflow is still immature stage of development, not even a recognized standard. But its application has already been launched in the Express, indicating the market's demand for job-flow framework are urgent and enormous. Backgrounds of o

  • Openfire Plugin Developer's Guide

    Introduction Openfire features plug-ins are enhanced. This document is a guide to developers to create plug-ins. The structure of a plug-in Plug-ins Plug-ins openfireHome stored in the directory. When deploying a plug-in jar or war file, it will automatic

  • js events dynamically add and write-off

    IE's JScript existence of memory leak bug must we all know or have heard of. This is because of IE's memory recovery manager of a design error. When we create a prepared script when a cross-reference, for example, the following code: window.o ...

blog comments powered by Disqus
Recent
Recent Entries
Tag Cloud
Random Entries