Zend ACL is the Zend Framework’s solution for authorization. It is indeed a flexible and standard method to insure that the users gain access to only what they are authorized.
Key objects when dealing with Zend_ACL are
- Role : a ‘group’ of users.. example ‘guest’ or ‘admin’
- Resource: Typically the ‘controller’
- Privilege : Typically the ‘action’
By making the Zend Resource and Privilege correspond to the Controller and Action respectively, we can automate the privilege checking process(the request object gives us access to the controller name and action name). Remember that while authentication is a one-time affair, authorization needs to be checked on every page fetch.
We therefore create a ‘front plugin’ and code the ‘preDispatch’ function (automatically gets triggered on EVERY request) to check whether the controller and action corresponding to the request are within the access level of the role assigned to the user. If not, we modify the controller/action to display the auth/login page.
Once this system is setup, it is completely self sustaining.. i.e. only the database tables need to be updated in case controllers/actions are added/removed. The following describes the approach that I use in my projects to automate Authorization.
Start off by creating a table of ALL controllers and actions in your application (Note that missing even a single controller or action could lead to accessibility problems)
Next, identify the Roles that you would like to assign.. Roles/groups that are typically used are ‘guest’, ‘author’,’admin’ etc. The idea is to control access using these roles and then assign users to these roles. This makes management easy (by avoiding per-user privileges).
For the sake of simplicity, let us assume that the roles in our sample app are ‘guest’ and ‘admin’. By default, all users are granted ‘guest’ access.
Our user table has the structure as shown above (the password field can be skipped if you use a third party like LDAP for authentication). After successful authentication (using Zend_Auth), the user_role field is stored in a session variable for easy global access.
Its now time to focus on our main ACL table. In all my applications, I create a database table named myacl with the following fields:
For populating this table, we will use the table of controllers and actions that we developed earlier. Then, carefully assign roles to the Resources/Controllers and Privileges/Actions. Our security criteria is "Everyone should have access to all the areas except the main controller’s index, view and update actions, which requires the Admin role".
The role assignment below captures this scenario:
Note that the guest role name(our default role) is granted access to error (the error controller/error action automatically handles errors in the zend framework and we need all to have access to the displayed error page)
The next important step is to define "role inheritance". In our example, if a user is an ‘admin’ user, he/she should automatically inherit all guest privileges. In order to make this easily programmable, we will create a table named acl_role:
When creating Zend_Acl_Role objects, the object corresponding to the guest object must already be created so that the admin object can inherit from it. The "create_order" field helps us in automating this process (It is possible to inherit from multiple roles but we will not consider that in this example). Also, note that acl roles must be unique within the scope of the application.
With this base, we can now code our custom ACL object.
We create it as a singleton object in the appropriate directory. MyAcl::getInstance() will retrieve an instance of our acl object for use in the plugin (next step)
- Loop through all the rows in myacl table joined with acl_role (the order of selection is by the create_order field) – You can also create a view on your database to return this join
- Note that the database parameters have been set up in our index.php file using Zend_Db::create. Zend_Db_Table.setDefaultAdapter($db) is also assumed to have been executed in the index file.
- Establish the Zend_Acl_Reso
urce and Zend_Acl_Role objects with the appropriate inheritance
- A second pass through the acl’s uses the ‘Allow’ command to grant privileges as defined in the myacl table
protected static $_instance=null;
private function __construct()
protected function _initialize()
//the db adapter has been set in the index..use it here!
$db = Zend_Db_Table::getDefaultAdapter();
$roles = $db->fetchAll("select * from myacl inner join acl_role on
acl_role.acl_role_name=myacl.acl_role_name order by create_order");
$inherit = $role['acl_inherits'];
$this->addRole(new Zend_Acl_Role($role['acl_role_name']), $inherit['acl_inherits']);
//start with a clean slate..deny everything
$this->allow($role['acl_role_name'], $role['acl_resource_name'], $role['acl_privilege_name']);
public static function getInstance()
We next code the front plugin that consumes our custom acl class. The main points are interest are
- We create an instance and store our object in the session. Doing a database lookup and rebuilding the acl for every request could potentially slow down your app.
- The request object gives us access to the controller name and action name
- We retrieve the users role from session namespace ‘UserInfo‘ (that is set by the authentication module after successful lookup)
- Default role assigned is ‘guest’
- We use the isAllowed() function to check permissions and redirect to the login page if not allowed.
public function preDispatch(Zend_Controller_Request_Abstract $request)
//check for version in session..
$sess_acl = new Zend_Session_Namespace('aclNamespace');
$acl = MyAcl::getInstance();
$sess_acl->acl = $acl; //push into session for next time!
else //found in session..reuse
$acl = $sess_acl->acl;
$auth = Zend_Auth::getInstance();
//get the logged in users role from session..
$session = new Zend_Session_Namespace('UserInfo');
$role = $session->userRole;
$resource = $request->getControllerName();
$privilege = $request->getActionName();
//now do the actual check!
if (!$acl->isAllowed($role, $resource, $privilege))
Just to give you a complete picture of how this plugin is actually invoked, here is my index.php file
//get the ini file
$config = new Zend_Config_Ini('../application/config.ini', 'general');
//get a database handle for later use
$db = Zend_Db::factory($config->db);
$auth = Zend_Auth::getInstance();
//now, set the controller
$controller = Zend_Controller_Front::getInstance();
echo 'An unexpected error occurred';