Zend_Acl part 1: Misconceptions and simple ACLs
February 6, 2009 – 7:35 am Tags: Zend Framework, Zend_AclI’m going to be writing a weekly series of posts on Zend_Acl. This first post will clear up some common misconceptions regarding Zend_Acl, introduce creating ACLs for simple applications, and give some examples on using the ACL in both non-Zend Framework and Zend Framework applications.
Later in the post series I’ll be talking about some more advanced ways of utilizing Zend_Acl, and topics such as database-backed ACLs.
A russian translation of this post is available here, courtesy of Rashad Surkin.
Zend_Acl misconceptions
Many people think that the ACL “resource” and “privilege” are the same as the controller and the action. This is not true!
The resource in Zend_Acl can be anything – a controller, a file, a model…
The privilege, just like the resource, can be anything related to the resource – for example, it could be an action if the resource is a controller, or it could be “read” or “write” if it’s a file or a model.
Later in the series, I’ll show some other ways of using acl resources, privileges and roles.
Building a simple ACL
As mentioned earlier, Zend_Acl constists of resources, privileges, and additionally, roles. Resources can be anything ranging from controllers to files. Privileges are different levels of access on the resource. Roles determine who can access a resource, and with what privileges. Roles can be users, user groups or anything you wish to associate such data with.
The very simplest way you can use Zend_Acl is building the ACL in code. This is often a useful approach for simple cases, where you only have a handful of resources and roles.
class My_Acl extends Zend_Acl { public function __construct() { //Add a new role called "guest" $this->addRole(new Zend_Acl_Role('guest')); //Add a role called user, which inherits from guest $this->addRole(new Zend_Acl_Role('user'), 'guest'); //Add a resource called page $this->add(new Zend_Acl_Resource('page')); //Add a resource called news, which inherits page $this->add(new Zend_Acl_Resource('news'), 'page'); //Finally, we want to allow guests to view pages $this->allow('guest', 'page', 'view'); //and users can comment news $this->allow('user', 'news', 'comment'); } }
Now, by creating a new instance of My_Acl, we could perform simple checks against the acl. But what is allowed, and for who?
The guest role gets a privilege called view on the resource page. Since the user role inherits from guest, it also gets this privilege. The news resource inherits from page, so everyone who has privileges on the page resource, has the same privileges on news. In the last line of the constructor, we add a privilege comment for the user role on news. Only the user role has the privilege comment in the news resource – guest does not.
Note: The names used in the example for the roles and resources are just identifiers. They could be 1, 2, or whatever, but it’s often easier to understand identifiers that are human-readable. However, when generating ACLs from databases or other source, it may not be necessary to have human-readable identifiers – the primary key from a database row will do just fine. Again, later in the series I’ll show an example of this.
Using the simple ACL
Using an ACL class is quite simple. You just call the method isAllowed with a role, resource and a privilege. The main difficulty is in determining what is the role, resource and the privilege.
How do we determine, what is the role? This can be a very simple if-clause: if there is a logged-in user, then the role is user, otherwise it is guest.
What about the resource? Depending on the application, this could be guessed from the file name included. For example, with our simple ACL, we could have a file called page.php and a file called news.php. page would check against the page resource, and news would check against the news resource.
And lastly, the privilege? When simply loading the page, you could use the view privilege. The code could later on check for other privileges: for example, the code could check if you have access to the comment privilege and display a comment box.
Here’s a really simple example:
$role = 'guest'; if(isset($_SESSION['auth'])) $role = 'user'; $acl = new My_Acl(); if($acl->isAllowed($role, 'news', 'comment')) { //Some code here to display a news box }
As you can see, it’s quite easy to use the ACL even without Zend Framework, and you can easily speed up development of non-ZF apps by using the ACL component as it will save time when you won’t need to implement complex authorization checking code.
The above example may be very simple, but it shows you the basic way ACLs are used.
Using the simple ACL in Zend Framework applications
In Zend Framework applications, the resource and privilege can often be determined from the request object.
Typically, we would create a plugin which checks the acl for us:
class My_Plugin_Acl extends Zend_Controller_Plugin_Abstract { private $_acl = null; public function __construct(Zend_Acl $acl) { $this->_acl = $acl; } public function preDispatch(Zend_Controller_Request_Abstract $request) { //As in the earlier example, authed users will have the role user $role = (Zend_Auth::getInstance()->hasIdentity()) ? 'user' : 'guest'; //For this example, we will use the controller as the resource: $resource = $request->getControllerName(); if(!$this->_acl->isAllowed($role, $resource, 'view')) { //If the user has no access we send him elsewhere by changing the request $request->setModuleName('auth') ->setControllerName('auth') ->setActionName('login'); } } }
We could have made the ACL static – instead of passing it in the constructor, we could have just created it in the preDispatch method. However, by passing it as a parameter, we make it easier to reuse this plugin. If we create a different ACL class, this plugin will still work with it without modifications.
Now that we have a plugin, we need to add it to the front controller in the boostrap:
$acl = new My_Acl(); //assuming $fc is the front controller $fc->registerPlugin(new My_Plugin_Acl($acl));
Now every request will be checked against the acl, and anyone without the view privilege would not get through.
Note: if you use the My_Acl class as-is, you may get an infinite loop! The code in the plugin is sending the user to Auth module’s AuthController’s loginAction. It also uses the controller’s name as the resource ID… but My_Acl does not have a resource called auth! So if you want to make it work, you need to add a resource called auth to the ACL, and have it inherit from page, as we already gave guest the necessary privileges to page.
But how do we check for the comment privilege?
You could add some code to the controller, which checks for the required privilege, and then sets a variable in the view to true:
public function someAction() { $role = (Zend_Auth::getInstance()->hasIdentity()) ? 'user' : 'guest'; //assuming $this->_acl contains the acl $this->view->canComment = $this->_acl->isAllowed($role, 'news', 'comment'); }
It may be a good idea to modify the code so that you won’t need to duplicate the role check. For example, you could store the role in the auth identity, or you could create an action helper which is used to access the acl and contains all relevant data.
In closing
Armed with this knowledge, you should be able to get started with Zend_Acl!
Next week’s post is going to deal with some more advanced Zend_Acl usage scenarios:
- Dealing with different resource types, such as controllers and files
- Dealing with different role types, such as users and user groups

33 Responses to “Zend_Acl part 1: Misconceptions and simple ACLs”
Great article Jani! It is exactly what i looking for during last few days, – A good example showing how to implement a nice ACL solution with Zend framework!
Thank you, it is realy clear and helpful!
Looking forward your next article on this topic!
By Lukas on Feb 6, 2009
Hi Jani.
Though I don’t use ZF (Agavi rules!!!
) it’s great article, as always 
Thanks to your blog posts I really consider to give second chance to that framework.
Cheers, Alan
By Alan on Feb 6, 2009
Great initiative, Jani. I’m looking forward to reading the next few articles from you about this subject.
Cheers, Christian.
By Christian on Feb 9, 2009
This is nice shortcut in understanding ACLs.
But ACLs are not really useful in so simple cases, most of the time there is a super users, that manages permissions and resources, linking them to roles.
Most of the time, resources are dynamic, they stay in a databases.
Is there a SANE way of storing ACLs in databases as generic as they are, and not doing any hackish stufs like storing them in hackish values to be exploded thereafter in php ?
Drawbacks observed:
- always querying the databases
- caching (until some superuser changes)
etc …
tell more on these real life situations for our mortal souls
By iongion on Feb 10, 2009
iongion,
In some extremely simple cases ACLs aren’t necessary. For example, one of my projects involved requiring login for all users for everything.
And for dynamic/database backed ACLs, that’s coming next week, so stay tuned!
This weeks ACL post about handling different kinds of roles and resources etc. will go up tomorrow.
By Jani Hartikainen on Feb 10, 2009
That was great! Another thing people get confused about is the relationship of ACL and Directory (ex. LDAP). They are not on the same plane of utility. It would be good to enlighten the community on such a subject.
By drydenmaker on Feb 11, 2009
Hi Jani.
This is a great article, and i want to translate it (and other articles in series) to Russian if you don’t mind.
By Oleg Lobach on Feb 12, 2009
Oleg, you are welcome to translate the articles. Just point out that the original was written by me and put a link back to this site
By Jani Hartikainen on Feb 12, 2009
Jani, no problem, make sure
By Oleg Lobach on Feb 12, 2009
Jani, I’m fairly new to ZF but it looks to me like you could make this a little more generic by getting the action too…
$resource = $request->getControllerName();
$action = $request->getActionName();
if(!$this->_acl->isAllowed($role, $resource, $action)) {…
Am I out to lunch on this?
btw: good article and thanks!
By Rick on Feb 13, 2009
You are indeed correct there Rick. You could use the action as the privilege like that if you want
By Jani Hartikainen on Feb 13, 2009
I see this is where i need to be. I’ve been using ZF for around a year now and its great. It covers a ton of areas. But that also seems to be the drawback. I find myself doing things the long way for not knowing a particular method exists in ZF. Am I missing some books or websites that detail best practices or starting points of building applications? The reference is good for….a reference but you have to know exactly what it is you are looking for.
This article really helped me with a mess I was beginning to make out of authentication schemes all because I had not run across the right parts of the ZF reference at the right time.
Thank you sir for this article.
By Phil on Feb 13, 2009
Thanks for the article. Could you please mention MVC best practices on where in the filesystem you would put these new classes “My_Plugin_Acl” & “My_Acl”? Thanks.
By Chaz Gilbert on Feb 24, 2009
You’d usually put them to library/My/Plugin/Acl.php and library/My/Acl.php
You may also want to consider using Zend Framework’s naming conventions for the plugin: My_Controller_Plugin_Acl
By Jani Hartikainen on Feb 24, 2009
Why do you create a new class extending Zend_Acl? You’re not modifying its behaviour, you’re not extending its functionality etc. it’s bad OOP. You can create a factory that configures and returns Zend_Acl object, this way your class has a distinct responsibility of just configuring the Acl and class hierarchy is simpler. The code should also be more testable this way.
By foobar on Mar 2, 2009
If you read part 3 you will notice it uses a factory =)
The reason that it’s not used earlier is because simpler classes don’t necessarily need one, and it also helps to keep the post itself easier to digest as it focuses more on the actual task at hand instead of building architechture around it which isn’t really even required.
By Jani Hartikainen on Mar 2, 2009
This article (and the next 2) look very promising … I have read it globally, and I think it rocks!
By Koen on Mar 3, 2009
Many thanks for this article, it’s by far the best one I could find on the topic and it really helped me making sense of ACL. Keep up the good work!
By Laurent on Mar 18, 2009
hi am newbie to zend framework can u tell me where to add the following code
$role = ‘guest’;
if(isset($_SESSION['auth']))
$role = ‘user’;
$acl = new My_Acl();
if($acl->isAllowed($role, ‘news’, ‘comment’)) {
//Some code here to display a news box
}
and can send me the source code to my email id(anandhi.cse@gmail.com)??
By Anandhi on Aug 31, 2009
finally a tutorial that works!!! thanks
By Pedro Bento on Apr 14, 2010
most of the time resources are dynamic they stay in a databases!
By mask3d on Jul 28, 2010