For a recent project, we built a rails application that accepted logins for two different classes of user. It was logically two applications, but since they both worked on the same domain model, we made them the same physical application, for simplicity.

One class of user was the customer of our client. These users were associated with their organization, so we used an “are you logged in?” type of authorization scheme, where any user in the organization could view and modify that organization’s information, but could view and modify no other organization’s information.

The second class of user was broadly termed “admin” users, and was basically people within our client’s company. These users had varying permissions, based on their roles in the company. Because they had varying authorities, we needed a better authorization system than “are you logged in?”

The system we came up with was fairly novel, though not as good as the easy role-based authorization that I read about yesterday. I thought I’d write it up anyways. The system was basically the same as any role-based permissioning system, but the things we decided to apply permissions to were actions.

So there were users, roles, and permissions. Users stored the usual stuff. User has_and_belongs_to_many roles. Roles have a name. Role has_and_belongs_to_many permissions. Permission has a controller and an action.

Thanks to the conventions of rails, we were able to define permissions such as “controller = *, action = show” and add that to the “read-only” role. We deviated from rails’s conventions in a couple of places, but it turned out to be few enough that we were able to set up a few simple permissions, and group them into the roles that the customer needed.

The big advantage of this system was that we needed to write the authorization code once: verify that the current user is allowed to execute the current action.

A disadvantage is that pages didn’t necessarily know if they were linking to a permission denied error. We probably could have resolved this, but we felt that it would work out OK if all the functionality was advertised to everyone that had read access, and if someone needed more functionality than they had, they’d click a link, get a friendly “permission denied, but ask your local admin if you need more access than you have” page.

I skipped all the code in this post, but hopefully you get the gist.