http://www.perlmonks.org?node_id=547708


in reply to Optimising a flexibile privilege system

Clinton,

Since you asked me via email to comment on this query, with specific reference to Bricolage, let me tell you how it works in Bricolage.

First, there are no permissions granted to individual users or to individual objects. It just made the schema too complex. So we only have groups of users and groups of objects that function as subjects and objects in Bricolage.

When you load an object from the database, the IDs of the groups of which it is a member are also loaded, in the same query. This list of group IDs is available via a call to get_grp_ids().

To check a permission, an object is passed to the user object's can_do() method, along with the permission in question. So if I want to know if a user has Edit permission to an object, I simply do something like this: if ($user->can_do($obj, EDIT)) {...}. The can_do() method then compares the object's group IDs against an ACL loaded for the user.

The user object is cached in the session, so it only gets loaded once for each user. Whenever permissions change, a flag is set in the system-wide cache and all user sessions automatically reload the user whenever it is set, so that permission changes are always immediate. This is not ideal, but generally expiring all users is more efficient that expiring all objects.

The ACL contains a hash mapping object group IDs to their permissions. So all can_do() has to do is iterate over this hash, find all of the relevant group IDs that the object is in, and compare the permissions.

Now, I wrote this a _long_ time ago, and it's far from ideal. It used to be that each object had to have its group IDs loaded in a separate query, and as you can imagine this made permission checking (and therefore Bricolage) extremely slow. It was _much_ better after all objects started loading their group IDs at the same time that they were loaded.

Now, as to your questions, I have the following feedback:

HTH,

—Theory