Experience with Zend_Acl and usage example

So I decided to write a bit about my experience and implementation of the Zend_Acl component, it’s a bit rough but I hope it gives an idea of how to possibly implement Zend_Acl. Let me know if there’s anything not very clear, I’m no english major so there’s bound to be some awful sections.



Background


So where I work, at RainStorm Consulting, we have a large web application system that drives parts of client’s websites. It currently does not have a public facing site that I could provide for more information, but it’s something that’s evolved over time to facilitate common needs among clients, eventually turning into a central service-providing administration site that clients can go to one place for to administer various dynamic content. It’s also a multi-tenant system, currently only with basic privileges, super administrator, site administrator, and a basic user that can only edit their ‘profile’ for a couple applications. There’s now a client with desire for more fine-grained permissions so Zend_Acl fit the bill.

Implementation

After brainstorming a bit, what exactly we needed for permission control and much frustration wrapping my head around the idea of ACL, taking it’s full capabilities into my head and getting confused. I basically ended up at the end with an ACL implementation that is similar to Drupal’s. I didn’t go into a full implementation of the hierarchy that Zend_Acl offers for both resources and roles. Our system has modules(separate applications) which will map directly to a resource, so say NewsStorm will have a resource by the same name. A role will then have various resource & permission words mapped to it, with a flag for allow or deny. The basic schema is sketched out roughly in this diagram:

acl-schema

I still haven’t finalized the best way for providing possible permissions from a module, but possibly a central module file that al modules will have, possibly containing a class. Currently it’s stored in the modules table in the database, modules create a record there on installation. A simple field right now has a csv of permissions, for example NewsStorm might have “manage categories, new post, edit post, delete post, publish post” which are provided in the permission management, which is modeled after drupal’s.

Shot of the client’s version of this permission management tool:

Siteturbine-Acl

The actual setup so permissions can be checked happens in the core class in setupAcl(), it pulls everything from the database and builds the ACL tree. We have 2 core roles, Administrator which is just hard-coded and Site Administrator which exists in the database and is meant for almost full control over every module for a site. We fetch all the roles and add them, along with resources.

$acl = new Zend_Acl();

$roles = Siteturbine_Acl_Role::find('all', array('parent_id is null'));
foreach($roles as $role) {
	$acl->addRole($role);
}
$resources = Siteturbine_Acl_Resource::find('all', array('parent_id is null'));
foreach($resources as $resource) {
	$acl->add($resource);
}
$acl->allow('Administrator', null, null);

foreach($roles as $role) {
	$query = "SELECT ro.name as role,re.name as resource,GROUP_CONCAT(rr.permission SEPARATOR ',') as perm
  FROM acl_roles ro
  LEFT OUTER JOIN acl_resources_roles rr ON rr.role_id = ro.id
  LEFT OUTER JOIN acl_resources re ON re.id = rr.resource_id
  WHERE ro.id = ? AND rr.allow = 1
  GROUP BY rr.resource_id";
	$allows = Siteturbine_Acl_Resource::findBySql(array($query, $role->id));
	$has_allow = false;
	foreach($allows as $a) {
		$has_allow = true;
		$acl->allow($role, $a->resource, explode(',', $a->perm));
	}
	if($has_allow) {
		$acl->allow($role, $a->resource, null);
		$acl->allow($role, $a->resource, 'view');
	}

	$query = "SELECT ro.name as role,re.name as resource,GROUP_CONCAT(rr.permission SEPARATOR ',') as perm
  FROM acl_roles ro
  LEFT OUTER JOIN acl_resources_roles rr ON rr.role_id = ro.id
  LEFT OUTER JOIN acl_resources re ON re.id = rr.resource_id
  WHERE ro.id = ? AND rr.deny = 1
  GROUP BY rr.resource_id";
	$allows = Siteturbine_Acl_Resource::findBySql(array($query, $role->id));
	foreach($allows as $a) {
		$acl->deny($role, $a->resource, explode(',', $a->perm));
	}
}

So tons of stuff going on in here I suppose, basically I query out the resource-permission maps into separate rows that I can loop through and call $acl->allow() or $acl->deny() as appropriate. If a role has any allow permission at all, I also set a hard-coded allow to the ‘view’ permission, which I use as a way to see if someone has ANY module permission at all, used in navigation.

After all that, I can call a helper type function I have for checking if the current user has permission for a specific area or task. This function takes care of automatically getting the current user and also the module if one isn’t specified.

	function isAllowed($permission, $module=null)

so $this->isAllowed(’new post’) might return true if the current user has a role that allows the ‘new post’ permission on the current module.

This was a pretty rough post, but I’m not so great at writing but I hope it might be useful. Let me know if it could use more clarification, I probably glossed over a lot.




Technorati Tags: , ,

Tags: , ,

No Responses to “Experience with Zend_Acl and usage example”

  1. Bruno Says:

    Hi Jeremy, I would like to discuss the MacBNetGatewayEditor with you, but I can’t find a way to directly contact you. So, if you read this, please send me an email. Thanks in advance.

  2. jerome Says:

    You can contact me at:

    jerome AT jeremyknope DOT com

    I’d email you but you didn’t leave an email in the comment :) hope you see this comment then!

Leave a Reply

You must be logged in to post a comment.