Simple role-based access control plugin for Rails controllers and views -- cloned from Mathew Abonyi's (mabs29) repo: http://mabs29.googlecode.com/svn/trunk/plugins/simple_access_control
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
lib
tasks
test
README
Rakefile
init.rb
install.rb

README

SimpleAccessControl
===================

Acknowledgements: I give all credit to Ezra and Technoweenie for their two plugins which
inspired the interface design and a lot of the code for this one.

SimpleAccessControl is a streamlined, intuitive authorisation system. It derives heavily from
acl_system2 and has made clear some problems which plagued me when first using it. Some
fixes to acl_system2's design:

      * a normal Rails syntax:
            access_rule 'admin', :only => :index
            access_rule '(moderator || admin)', :only => :new
      * error handling for helper methods (permit? bombed when current_user == nil)
      * one-line parser, easy to replace or alter
      * proper before_filter usage, meaning access rules are parsed only when needed
      * no overrideable default (which I found counter-intuitive in the end)

Also, it has two methods, access_control and permit?, for those moving from acl_system2.

But, let me stress, everyone likes a slightly different system, so this one may not be
your style. I find it synchronises very well with the interface of Acts as Authenticated (even
though I have modified it so much that it's now called Authenticated Cookie).

INSTALLATION
============

Create the following migration:

  create_table "roles", :force => true do |t|
    t.column "title", :string
  end
  create_table "roles_users", :id => false, :force => true do |t|
    t.column "role_id", :integer
    t.column "user_id", :integer
  end

In your User model, you must have:

  has_and_belongs_to_many :roles
  
In your Roles model, you must have:

  has_and_belongs_to_many :users

Your controllers must have the following two methods or variants of them:

  # Returns a User object
  def current_user
    @current_user
  end

  # Returns true or false if a User object exists for this session
  def logged_in?
    @current_user.is_a? User
  end


SPECIAL NEEDS
=============

If you want to permit anonymous users without demanding that they are logged in, first you
must ensure that logged_in? returns true in all cases, otherwise permission will be denied.
The following approach should work:

1. Create the 'guest' and 'user' roles, e.g.:

  guest = Role.create(:title => 'guest')
  user = Role.create(:title => 'user')

2. In your registration/user creation area, ensure all real users have the 'user' role, e.g.:

  @user = User.create(params[:user])
  unless @user.roles.any? { |r| r.title == 'user' }
    @user.roles << Role.find_by_title('user')
  end
  @user.save  

[At this point you have two options: a real or virtual anonymous account]

First Approach: Real Anonymous User

  3a. Create an anonymous user, e.g.:

    @anonymous = User.create(:login => 'anonymous', :password => '*', :activated => true)

  4a. Add the role to the Anonymous user (in a migration or in script/console), e.g.:

    anonymous.roles << Role.find_by_title('guest')
    anonymous.save

  5a. In your ApplicationController, set unauthenticated users as 'anonymous', e.g.:

    before_filter :default_to_guest

    def default_to_guest
      self.current_user = User.find_by_login('anonymous', :include => :roles) unless logged_in?
    end


Second Approach: Virtual Anonymous User

  3a. In your ApplicationController, create a virtual anonymous account if unauthenticated:

    before_filter :default_to_virtual_guest
    def default_to_virtual_guest
      self.current_user = self.anonymous_user unless logged_in?
    end

    def anonymous_user
      anonymous = User.new(:login => 'anonymous', :name => 'Guest')
      anonymous.roles << Role.new(:title => 'guest')
      anonymous.readonly!
      anonymous
    end


USAGE
=====

The plugin is automatically hooked into ActionController::Base.

In your controllers, add access rules like so:

  access_rule 'admin', :only => :destroy
  access_rule 'user || admin', :only => [:new, :create, :edit, :update]

Note the use of Ruby-style operators. These strings are real conditionals and should be treated as
such. Every grouping of non-operator characters will be considered a role title.

In your views, you can use the following:

  <% restrict_to 'admin || moderator' do %>
    <%= link_to "Admin Area", admin_area_url %>
  <% end %>
  
AND

  <%= link_to("Admin Area", admin_area_url) if has_permission?('admin || moderator') %>

There are also transitional methods which help you move from acl_system2 to this plugin -- I do this
not to denegrate acl_system2 but because I did this for myself and decided to include it. The two
systems are rather similar.

Also, there are two callbacks, permission_granted and permission_denied, which may define in your
controllers to customise their response. For example:

  def permission_granted
    logger.info("[authentication] Permission granted to %s at %s for %s" %
      [(logged_in? ? current_user.login : 'guest'), Time.now, request.request_uri])
  end
  
  def permission_denied
    logger.info("[authentication] Permission denied to %s at %s for %s" %
      [(logged_in? ? current_user.login : 'guest'), Time.now, request.request_uri])
  end


That's it!


VARIATION BY MABS29