You may be interested in reading this article by Steffen Bartsch. It summarizes all authorization plugins for Ruby on Rails, and I am sure it will help you find your solution (although this article is about Rails plugins, the concepts are easily exportable outside Rails).
Steffen also built his own plugin, called "Declarative Authorization" which seems to match your needs, IMHO:
- on the one hand, you define roles (such as "visitor", "admin"...). Your users are associated to these roles (in a many-to-many relationship). You map these roles to privileges (again in a many-to-many relationship). Each privilege is linked to a given context. For example, the role "visitor" may have privilege "read documents". In this example, "read" is the privilege, and it is applied to the "documents" context.
- Note: in Steffen's plugin, you can define a hierarchy of roles. For example you might want to have the "global_admin" role include the "document_admin" role, as well as the "comment_admin" role, etc.
- You can also defines hierarchies of privileges: for example, the "manage" privilege could include the "read", "update", "add" and "delete" privileges.
- on the other hand, you code your application thinking in terms of privileges and contexts, not in terms of roles. For example, the action to display a document should only check whether the user has the privilege to "read" in the "documents" context (no need to check whether the user has the "visitor" role or any other role). This greatly simplifies your code, since most of the authorization logic is extracted elsewhere (and perhaps even defined by someone else).
This separation between the definition of the user roles and the definition of the application-level privileges guarantees that your code will not change every time you define a new role. For example, here is how simple the access-control would look like in a controller :
class DocumentController [...]
filter_access_to :display, :require => :read
def display
...
end
end
And inside a view:
<html> [...]
<% permitted_to?(:create, :documents) do %>
<%= link_to 'New', new_document_path %>
<% end %>
</html>
Steffen's plugin also allows for object-level (ie. row-level) access-control. For example, you might want to define a role such as "document_author" and give it "manage" privilege on "documents", but only if the user is the author of the document. The declaration of this rule would probably look like this:
role :document_author do
has_permission.on :documents do
to :manage
if_attribute :author => is {user}
end
end
That's all there is to it! You can now get all the documents that the user is allowed to update like this:
Document.with_permissions_to(:update)
Since the "manage" privilege includes the "update" privilege, this will return the list of documents whose author is the current user.
Of course, not every application will need this level of flexibility... but yours might.