0.0
No commit activity in last 3 years
No release in over 3 years
Simple access control on controller basis
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

 Project Readme

AccessChecker

AccessChecker is a simple replacement for ACL9, a role-based authentication gem. AccessChecker is primarily oriented for functioning as a before_action role authentication scheme for Rails controllers.

Basic concepts

Authentication is often called for on a controller-by-controller basis, restricting actions to users who possess certain roles. AccessChecker (current version) assumes only one role per user. AccessChecker requires a current_user method accessible at the controller level and which returns a User object.

AccessChecker adds, to the User model, role accessor methods: has_role?, has_role!, get_role

Structure

  • necessary models: user, roles, roles_users (join table)
  • necessary migrations (for access_checker): roles, roles_users (join table)

Defaults assumed

User is the subject model: indicate by inserting the following macro after the class definition:

    acts_as_authorization_subject

Role is the role model: indicate by inserting the following macro after the class definition:

   acts_as_authorization_role

Note: the gem allows the default model/table names to be changed, but I haven't built tests for verifying that the changes will work.

   class Role < ActiveRecord::Base
     acts_as_authorization_role
   end

   class User < ActiveRecord::Base
     acts_as_authorization_subject
   end

Migrations required

The roles table must be created (sorry, no generator yet) Some of the fields are legacy from acl9 and currently are not used.

  create_table "roles", :force => true do |t|
    t.string   "name",              :limit => 40
    t.string   "authorizable_type", :limit => 40
    t.string  "authorizable_id"
    t.boolean "system", :default=>false
    t.datetime "created_at"
    t.datetime "updated_at"
  end

and the join table

    create_table :roles_users, :id => false, :force => true do |t|
      t.column  :user_id, :integer
      t.column  :role_id, :integer
    end
      add_index :roles_users, :user_id

Usage

At the head of every controller for which you wish to control user access, you'll need to place an access_control macro which is used to generate a before_action for the authorization checks. The macro takes a hash of role specification parameters. These must be specified prior to the macro and then referenced as the macro's parameter parameter. I cannot be specified in-line because Rails is treating it as a before_action and so expects a before_action type of ( :only =>, :except => ) hash which would then apply to the before_action itself and thus bypass any explicit checking.

Unauthorized access yields an exception: AccessChecker::AccessDenied . Syntax errors in formulating the control parameters will also raise an exception: AccessChecker::SyntaxError . You'll probably want to catch those exceptions and handle them gracefully, probably in your ApplicationController.

Notice that roles, limit_types, and controller actions are all expected to be symbols.

You have complete freedom to define roles to be whatever you want: except for the reserved words: :all, :anonymous. The usage of :all, :anonymous is explained with the following logic.

  • if current_user.nil?, then proceed as :anonymous if :anonymous is referenced in the role_control_hash
  • if user's role is not referenced, then proceed as :all if :all is referenced in the role_control_hash
  • else proceed and evaluate the role_control_hash with user's role

This means that :all will only be invoked if a user has a role which is NOT specified in the role_control_hash and if :all is specified in the hash. In that sense :unspecified would be more accurate than :all, but :all is shorter and handier to work with. And it means that :anonymous will only be invoked if current_user.nil? is true and if :anonymous is specified in the hash.

The access limitation types are:

  • :allow, :to, :only -- control what access is allowed; all else will be denied
  • :deny, :except -- control what is denied; all else will be permitted

The action list can be empty; in which case, for :allow, all actions are permitted; and for :deny, no actions are permitted. If both limit_type and action_list are missing, then :allow => [] will be assumed.

class AnyController < ApplicationController

   control_parameters = {
       :admin   => { :allow => [] },
       :manager => { :deny  => [ :delete, :edit ] },
       :member  => { :allow => [ :index, :show  ] },
       :anonymous => { :allow => [:index ] },
       :all       => { :deny  => [:edit, :update] }
   }

   access_control control_parameters

Catch exceptions:

class ApplicationController < ActionController::Base
   rescue_from AccessChecker::AccessDenied do |e|
     # do something here
   end

Acknowledgements

AccessChecker was influenced by the acl9 gem (https://github.com/be9/acl9).