Zend_Acl and MVC Integration Part I (Basic Use)

June 23, 2008

Tutorials, Zend Framework

By Aldemar Bernal

So, what is wrong with Zend_Acl and the current MVC implementation in the Zend Framework? there is nothing wrong, it is just that it gets not too obvious for developers how to achieve an optimal integration between these two important parts of the framework.

First at all, this article is based on the following Zend Framework Proporsal (link), by this moment this proposal is in Pending Recommendation state.

Well, how it works? There are two key components in this proposal:

  1. A Front Controller Plugin: This component resolves if the current user has access to the page which is being opened.
  2. An Action Helper: This component allows you to check whether the current user has access inside a controller.

Based on these two components, let’s try them with an example. Let’s talk about a website like DevZone, we would need a controller that work with the user management and another one which will deal with article management, as well we need 3 types of users (roles), one for guests, one for writers and another one which will approve the articles; resuming, we have:

Resources:

  1. user controller.
  2. article controller.

Roles:

  1. Guest.
  2. Writer.
  3. Admin.

Setting up the Zend_Acl component

After defined what we want to do, the next step will create a Zend_Acl instance which will reflect our model.

/** Creating the ACL object */
require_once 'Zend/Acl.php';
$myAcl = new Zend_Acl();

Creating the roles

Now we create the roles in our Zend_Acl instance.

/** Creating Roles */
require_once 'Zend/Acl/Role.php';
$myAcl->addRole(new Zend_Acl_Role('guest'))
      ->addRole(new Zend_Acl_Role('writer'), 'guest')
      ->addRole(new Zend_Acl_Role('admin'), 'writer');

Creating the resources

And then we create the resources needed (one per controller) and their relationship with the roles we created.

/** Creating resources */
require_once 'Zend/Acl/Resource.php';
$myAcl->add(new Zend_Acl_Resource('user'))
      ->add(new Zend_Acl_Resource('article'));

Creating the permissions

Now that we added the roles and resources to our Zend_Acl instance, it’s time to explain what actions must be available to which roles.

  1. Guest won’t have access to edit, add or approve an article.
  2. Writer won’t have access to approve an article.
  3. Admin will have complete access.

/** Creating permissions */
$myAcl->allow('guest', 'user')
      ->deny('guest', 'article')
      ->allow('guest', 'article', 'view')
      ->allow('writer', 'article', array('add', 'edit'))
      ->allow('admin', 'article', 'approve');

Creating the access denied view file

We will need to create a view and an action which will address all those denied users, in order to do it, first we create a new action in our error controller:

class ErrorController extends Zend_Controller_Action
{
    ....

    public function deniedAction()
    {
    }

    ....
}

And then we create our view file (/application/views/scripts/error/denied.phtml) with some warning message:

<h1>Error</h1>
<h2>Access denied</h2>
<p>You are trying to access an area which you have not allowed.</p>

Finishing the configuration

Okay, we have setup our Zend_Acl configuration, so far, it doesn’t look like something new, but the next step is register the controller plugin, this important part takes the Zend_Acl instance we created and then validates it against the current page being accessed by an user.

/** Setting up the front controller */ 
require_once 'Zend/Controller/Front.php'; 
$front = Zend_Controller_Front::getInstance(); 
$front->setControllerDirectory('path/to/controllers'); 
 
/** Registering the Plugin object */ 
require_once 'Zend/Controller/Plugin/Acl.php'; 
$aclPlugin = new Zend_Controller_Plugin_Acl($myAcl);
$aclPlugin->setRoleName($currentUserRole);

$front->registerPlugin(new Zend_Controller_Plugin_Acl($acl, 'guest')); 

/** Dispatching the front controller */ 
$front->dispatch(); 

After this configuration is done, once an user enters in our application, depending the role he/she has the page will be displayed or an access denied page will be displayed.

For more information about this you can go to:

Zend_Acl & MVC Integration

and here is a small implementation source code of this:

Source Code

19 Responses to “Zend_Acl and MVC Integration Part I (Basic Use)”

  1. jvasc2007 Says:

    This post was very informative. I just wish that it would show which files the code was in.

    I am trying to create ab ACL and used a Action Helper for the logic. How do I register it on the bootstrap file?

  2. amitblues123 Says:

    When we implement roles using Zend_Acl are static or they are stored in database….
    Not able to understand above Tutorial for Zend_Acl-and-MVC-Integration-Part-I-Basic-Use…

  3. joostpluijmers Says:

    I have extended the both the Zend_Acl and Zend_Acl_Role_Registry in order to shape the logic into loading only relevant roles and permissions from the database. This took me quite some time because the Zend_Acl class may be configured with relative ease, extending it with a lot of functionality is not.

    Is there a simpeler way to load all relevant data from the db into the acl in a lazy manner?

  4. ami06 Says:

    I have installed Zend Framework 1.5.3.
    I created Dir Struct as
    Controller/
    Models/
    Views/
    index/
    index.phtml
    test.phtml

    I am able to get the output of index.phtml but when i type

    http://localhost/zf/public/test

    i am not getting the test file output it shows me error
    "Object not found!…"

    plz help me to resolve this problem.

    Thanx,
    with kind regards,
    Amit

  5. vertigoone Says:

    You are right, sorry, that’s a typo.

  6. shannonless Says:

    It’s a good article for basic use.
    but in fact , we can’t do like this in real project.
    For advance usage of Zend_Acl , we may combin other components like Zend_Config,Zend_Cache , etc..

  7. herrserker Says:

    Shouldn’t it be
    $front->registerPlugin(new Zend_Controller_Plugin_Acl($aclPlugin, ‘guest’));
    ?

  8. herrserker Says:

    Shouldn’t it be
    $front->registerPlugin(new Zend_Controller_Plugin_Acl($aclPlugin, ‘guest’));
    ?

  9. vertigoone Says:

    Hi mikovali, thanks for your positive feedback, to use nested roles is mostly recommended because not using them could address security flaws since you will have to create permissions for every role you have instead of inherate them, meaning that if you have N roles, you will have to create N*(Number of Resources) permissions that will be larger that just inherate permissions, that said, if you 10 roles and 100 resources, you’ll get 1000 permissions instead that maybe 300-400 using nested roles.

    About storing acl into a DB, I will talk later about how to integrate datasources into Acl with another proposal I wrote, so stay tuned!.

    Aldemar

  10. vertigoone Says:

    Hi mikovali, thanks for your positive feedback, to use nested roles is mostly recommended because not using them could address security flaws since you will have to create permissions for every role you have instead of inherate them, meaning that if you have N roles, you will have to create N*#Resources permissions that will be larger that just inherate permissions, that said, if you 10 roles and 100 resources, you’ll get 1000 permissions instead that maybe 300-400 using nested roles.

    About storing acl into a DB, I will talk later about how to integrate datasources into Acl with another proposal I wrote, so stay tuned!.

    Aldemar

  11. mikovali Says:

    First off, thank you so very much for this :)

    But if I use Doctrine, is it wise to use nested set for roles?

  12. marcuslange Says:

    The best way I’ve found to use the ACL with a database is to have an on save handler that builds the ACL and serializes it to a cache (Zend_Cache is a handy tool) when the database is updated.

    This allows you to store the data in the database, use the Zend_Acl, and Save trips to the DB.

  13. jplush76 Says:

    @grandgeorg
    I think you may not have read or understood the ACL documentation because it sounds like you’re trying to use a framework as to not re-invent the wheel yet you rolled your own ALC that reinvented the wheel.

    The Zend ACL can be created once, all the resources, roles and perms set up, then serialzed and stored in something like memcached a flat file or DB for increased performance. The backend store can be a database if you wish, you just extend the ACL class and load up your roles, resources and perms from the DB, then loop and add the rights.

  14. vertigoone Says:

    I’ll talk later on in other articles (remember, this was Part I) about more MVC + Zend_Acl, for example to query from a controller if a user has right to edit an article.

    Sometimes it’s not necessary to take Acl from a database, for example in a website as the one shown in the article (devzone), there is no moment where an Admin would like Guests to approve articles =P, so, it can be hardcoded. I’m writing right now another article about other proposal I have, that talks about those cases where you need to change Acl in the fly, so, not hardcoded but using anything you’d like (a DB, a config file, etc), stay tuned =D

  15. vertigoone Says:

    All the code comes in the bootstrap or wherever you want the Acl to be defined (all but the deniedAction of course). The source code shows you the Use Cases implemented in the proposal, so, you will need to read the UCs to understand that code.

  16. grandgeorg Says:

    Nice tutorial.

    The problem with Zend_Acl is that nobody wants to hardcode roles, resources and permissions in some file (at least not me). I have database tables for user, roles, resources and permissions, so an admin can easily modify and extend them as needed.

    A db-query for the current user and the requested resource (action) is enough to determine rights and let the MVC act accordingly. There is simply no reason to use Zend_Acl as that would just double the db structure and the queries. – Know what I mean?

  17. skyblaze5 Says:

    I mean from this article and the example code that can be downloaded i can’t figure out the whole big picture. For example what code goes in what place? (bootstrap file? controller file? etc). It is somehow disconnected this code.

  18. weierophinney Says:

    Nice writeup, Aldemar! ACLs are often seen as an arcane subject in ZF, and they’re actually dirt simple, as you clearly illustrate. I also like the idea of the deniedAction() in your error controller.