Skip to content

Overview of Behavior

hollownest edited this page Sep 13, 2010 · 3 revisions

Declarative Authorization (decl_auth) allows you to define “roles” that can automatically be applied to ActionController and ActiveRecord access to verify authorization. I’ll describe ActionController but they function quite similarly.

config/authorization_rules.rb

The roles can define authorization to be “absolute” or to be “relative”

  • Absolute authorization describes permission on a method without reference to the specific objects involved.
    For example, a “user_manager” should be able to access the :index, :show, :edit, :update, :new, :create, and :destroy methods on the ‘Users’ controller, regardless of which user is involved.

  role :user_manager do
    has_permission_on :users, :to => :all
  end

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

  • Relative authorization describes permission on a method and allows you to reference an object of the related type to determine permission. For example, any user should be able to access :show, :edit, and :update on their own account, and :new and :create on any account (since the anonymous user has permission to create a new account – this might be different on your system, of course):

  role :guest do
    has_permission_on :users, :to => [:show, :edit, :update] do
      if_attribute :id => is {user.id}
    end
    has_permission_on :users, :to => [:new, :create]
  end

Note: guest is a special role that is assigned to users who have no other roles and anonymous users (with no current_user assigned).

  • Combined — of course, in most systems you would want both so you would just put these two together in the file.

Where do the roles come from?

You must define “role_symbols” in your User model, as described elsewhere. decl_auth uses this method from the current_user. current_user is a bit of the magic described further on.

Configure the ActionController to check permissions

To make this go, of course, you need to add a before_filter to the ActionController in question:


  class UsersController < ApplicationController
    before_filter :require_logged_in, :except => [:new, :create]

    filter_access_to :index
    filter_access_to :show, :edit, :update, :attribute_check => true

    # snip
  end

A closer look:

  • before_filter :require_logged_in is NOT part of decl_auth, but in my configuration it loads current_user which is used by decl_auth to find the roles a user possesses.
  • filter_access_to :show, :edit, etc – this loads @user from params[:id] and uses it to check the attributes in the authorization rules
  • filter_access_to :index – index does not load @user (first of all, params[:id] would not be set!); this works because it is an absolute permission — if you have user_manager, you have access.

Magic under the hood

  • decl_auth guesses that User is the right class based on the name of the ActionController class (true??). If you were checking attributes on ProductsController, it
    would look for the Product model to load from params[:id].
  • decl_auth uses the current_user method in the ActionController to check the current user. I have this defined in application.rb:

  helper_method :current_user
  def current_user
    // load current user from session
  end

  • As Steffen has described elsewhere, you filter_access_to is also a before_filter, so if you want things loaded before it gets run, you
    need to pay attention to where your before_filters are located in the call chain.