Controller integration
To manually protect your controller actions with Aegis, check permissions before an action like this:
class NotesController def update @note = Note.find(params[:id]) current_user.may_update_note!(@foo) @note.update_attributes!(params[:note]) end end
Because we used the bang variant to check permissions (may_update_note!
instead of may_update_note?
), Aegis raises an error if the check fails. Subsequent code (updating the note and rendering the view) will only be executed if the check passes.
Aegis offers a very comfortable mapping between your controller actions and permission rules With the automatic integration, Aegis does all permission checks in a before_filter. This way your actions do not need to concern themselves with permission checks.
A very simple use case is that every action in a controller is protected by the same permission action. Let’s say your permissions look like this:
class Permissions < Aegis::Permissions role :special_agent action :access_internal_affairs do allow :special_agent end end
To protected every action in SecretsController
by a check on current_user.may_access_internal_affairs!
include Aegis::Controller
and use the permissions
directive:
class SecretsController < ApplicationController include Aegis::Controller permissions :access_internal_affairs end
This assumes that your controllers have access to a method called current_user
that return the logged in user.
If your application uses RESTful controllers you can easily map permisision resources to your controller actions. With one line of code you can make sure that an action like NotesController#edit
is protected by a permission resource action like may_update_note!
.
We’re making two assumptions:
- Your controllers have a method like
current_user
that return the user that is presently logged in. If you are using Clearance, Devise or authlogic, this is probably already the case. - Your controllers have a method like
object
orload_record
that loads the record to be processed. This is the default in resource_controller and also a useful pattern to keep your controllers tidy.
Say you have defined the following permission resource:
class Permissions < Aegis::Permissions role :user resources :notes do allow :user end end
A controller that is protected by those permissions automatically looks like this:
class NotesController < ApplicationController include Aegis::Controller permissions :notes def update object.update_attributes!(params[:note]) end private def object @object ||= Note.find(params[:id]) end end
The permissions
directive maps the permission resource :note
to the actions of the controller. Hence the update
action is protected by a before_filter that calls current_user.may_update_note!(object)
.
By default each controller action maps to a permission action of the same name. The actions new
and edit
are aliased to create
and update
respectively.
If you need to map individual actions differently, you can provide an option that maps controller actions to specific permissions:
class ApartmentsController < ApplicationController include Aegis::Controller permissions :apartments, :map => { :gallery => :index_apartments } end
The permissions
directive takes an optional parameter hash which you can use to configure the integration mapping, for example:
permissions :notes, :object => :set_record, :user => :signed_in_user, :except => :index
The options available are:
-
:object
: The name of the method used to load the record that is to be processed by the controller. Default is:object
. -
:parent_object
: The name of the method used to load the parent object when mapping to a nested permission resources. Default is:parent_object
. -
:user
: The name of the method that returns the user that is currently signed in. Default is:current_user
. -
:permissions
: The name of your permissions class as string orClass
object. Default is'Permissions'
. -
:except
: The name of an action (or an array of actions) for which the automatic controller integration should be disabled. -
:only
: The name of an action (or an array of actions) for which the automatic controller integration should be enabled, leaving all other actions unprotected.
You might want to force yourself to add a permission
directive to every controller you write, so no controller is left unprotected. For this, add the following line to your ApplicationController
:
class ApplicationController < ActionController::Base include Aegis::Controller require_permissions end
Now Aegis will raise Aegis::UncheckedPermissions
whenever a controller forgets to guard itself with a permissions
directive.
To skip the forced permissions check, use skip_permissions
:
class SessionController < ActionController::Base include Aegis::Controller skip_permissions :only => [:new, :create] end
Options :only
and :except
are available and behave like for before_filter
.