Zend Framework: need typical example of ACL
Asked Answered
C

2

16

Can some one guide me for typical implementation example of ACL. Like 'admin' can access 'admin' module, 'user' can access 'user module', and guest can access 'open' pages.

Callida answered 6/3, 2011 at 9:18 Comment(2)
See the top answer to this previous question for an excellent implementation example: #2047108Landgraviate
ZF reference gives also not bad example: framework.zend.com/manual/en/zend.acl.refining.htmlScrub
S
25

I can paste you my ACL. It consists of three elements: acl.ini, ACL controller plugin (My_Controller_Plugin_Acl) and My_Acl class, and USER table. However it does not deal with modules, but with controllers and actions. Nevertheless it may give you some general idea about ACL. My use of ACL is based on the one in a book called "Zend Framework in Action".

USER table (privilege field is used for ACL):

CREATE  TABLE IF NOT EXISTS `USER` (
  `user_id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
  `email` VARCHAR(85) NOT NULL ,
  `password` CHAR(32) NOT NULL,
  `phone` VARCHAR(45) NULL ,
  `phone_public` TINYINT(1) NULL DEFAULT 0 ,     
  `first_name` VARCHAR(45) NULL ,
  `last_name` VARCHAR(45) NULL ,
  `last_name_public` TINYINT(1) NULL DEFAULT 1 ,
  `is_enabled` TINYINT(1) NOT NULL DEFAULT 1 ,
  `created` TIMESTAMP NOT NULL,
  `privilage` ENUM('BASIC','PREMIUM','ADMIN') NOT NULL DEFAULT 'BASIC' ,
  PRIMARY KEY (`user_id`) ,
  UNIQUE INDEX `email_UNIQUE` (`email` ASC) )
ENGINE = InnoDB;

acl.ini (I have four privileges, such that basic inherits from guest, premium inherits form basic and administrator for premium):

; roles
acl.roles.guest = null
acl.roles.basic = guest
acl.roles.premium = basic
acl.roles.administrator = premium

; resources
acl.resources.deny.all.all = guest


acl.resources.allow.index.all = guest
acl.resources.allow.error.all = guest
acl.resources.allow.user.login = guest
acl.resources.allow.user.logout = guest
acl.resources.allow.user.create = guest

acl.resources.allow.user.index = basic
acl.resources.allow.user.success = basic

My_Acl class (creates ACL roles and resources based on the ini file):

class My_Acl extends Zend_Acl {

    public function __construct() {
        $aclConfig = Zend_Registry::get('acl');
        $roles = $aclConfig->acl->roles;
        $resources = $aclConfig->acl->resources;
        $this->_addRoles($roles);
        $this->_addResources($resources);
    }

    protected function _addRoles($roles) {

        foreach ($roles as $name => $parents) {
            if (!$this->hasRole($name)) {
                if (empty($parents)) {
                    $parents = null;
                } else {
                    $parents = explode(',', $parents);
                }                    
                $this->addRole(new Zend_Acl_Role($name), $parents);             
            }
        }       
    }

    protected function _addResources($resources) {          

        foreach ($resources as $permissions => $controllers) {         

            foreach ($controllers as $controller => $actions) {
                if ($controller == 'all') {
                    $controller = null;
                } else {
                    if (!$this->has($controller)) {
                        $this->add(new Zend_Acl_Resource($controller));
                    }
                }

                foreach ($actions as $action => $role) {
                    if ($action == 'all') {
                        $action = null;
                    }
                    if ($permissions == 'allow') {
                        $this->allow($role, $controller, $action);
                    }
                    if ($permissions == 'deny') {                           
                        $this->deny($role, $controller, $action);
                    }
                }
            }
        }
    }

}

My_Controller_Plugin_Acl:

class My_Controller_Plugin_Acl extends Zend_Controller_Plugin_Abstract {

    /**
     *
     * @var Zend_Auth
     */
    protected $_auth;

    protected $_acl;
    protected $_action;
    protected $_controller;
    protected $_currentRole;

    public function __construct(Zend_Acl $acl, array $options = array()) {
        $this->_auth = Zend_Auth::getInstance();
        $this->_acl = $acl;

    }

   public function preDispatch(Zend_Controller_Request_Abstract $request) {

        $this->_init($request);        

        // if the current user role is not allowed to do something
        if (!$this->_acl->isAllowed($this->_currentRole, $this->_controller, $this->_action)) {

            if ('guest' == $this->_currentRole) {
                $request->setControllerName('user');
                $request->setActionName('login');
            } else {
                $request->setControllerName('error');
                $request->setActionName('noauth');
            }
        }
    }

    protected function _init($request) {
        $this->_action = $request->getActionName();
        $this->_controller = $request->getControllerName();
        $this->_currentRole = $this->_getCurrentUserRole();
    }

    protected function _getCurrentUserRole() {      

        if ($this->_auth->hasIdentity()) {
            $authData = $this->_auth->getIdentity();
            $role = isset($authData->property->privilage)?strtolower($authData->property->privilage): 'guest';
        } else {
            $role = 'guest';
        }

        return $role;
    }

}

Finally a part of Bootstrap.php where everything is initialized:

protected function _initLoadAclIni() {
    $config = new Zend_Config_Ini(APPLICATION_PATH . '/configs/acl.ini');
    Zend_Registry::set('acl', $config);
}

protected function _initAclControllerPlugin() {
    $this->bootstrap('frontcontroller');
    $this->bootstrap('loadAclIni');

    $front = Zend_Controller_Front::getInstance();

    $aclPlugin = new My_Controller_Plugin_Acl(new My_Acl());

    $front->registerPlugin($aclPlugin);
}
Stricklin answered 7/3, 2011 at 0:10 Comment(7)
Marcin , you always propose a new idea , and today's idea is save acl in ini file , good job my friendAminopyrine
@tawfekov. Thanks:-) But this is not fully my idea as I took from the book mentioned in my answer.Stricklin
hi , we can manage controllers and actions with this code. how i can manage modules access with this code?Landel
@afsane. In my example, the resources are defined as: acl.resources.allow/deny.CONTROLLER.ACTION. So, to add module, you would need to have something such asacl.resources.allow/deny.MODULE.CONTROLLER.ACTION. Also you would need to modify My_Acl class and Acl controller plugin to account for the MODULE.Stricklin
ya Marcin, i know , but my prob is : how set module in this code $this->allow($role, $controller, $action); i tested that like $this->allow($role, $module ,$controller, $action); or $this->allow($role, $module . ':' . $controller, $action); but these don`t work!Landel
@afsane. I would suggest making SO question asking about how to handle modules in ACL as I don't know myself very well. So I also would be interested how should it be done correctly.Stricklin
thank you! Got some problems with autoload this class but finaly it worksThorite
A
4

I have a simple example that might fits your needs

class Dagho_Acl_Main extends Zend_Acl {
    public function   __construct() {
        $anonymous = new Zend_Acl_Role("anonymous");
        $customer = new Zend_Acl_Role("customer");
        $admin = new Zend_Acl_Role("admin");
        $anonymousResource  = new Zend_Acl_Resource("acl");
        $defaultResource = new Zend_Acl_Resource("default");
        $customerResource  = new Zend_Acl_Resource("user");
        $adminResource  = new Zend_Acl_Resource("manage");


        $this->addRole($anonymous)
             ->addRole($customer)
             ->addRole($admin);
        $this->addResource($anonymousResource)
             ->addResource($defaultResource)
             ->addResource($customerResource)
             ->addResource($adminResource);


        $this->allow($anonymous, $anonymousResource);
        $this->allow($anonymous, $defaultResource);
        $this->deny($anonymous, $customerResource);
        $this->deny($anonymous, $adminResource);

        $this->allow($customer, $anonymousResource);
        $this->allow($customer, $defaultResource);
        $this->allow($customer, $customerResource);
        $this->deny($customer, $adminResource);

        $this->allow($admin, $defaultResource);
        $this->allow($admin, $anonymousResource);
        $this->allow($admin, $adminResource);
        $this->deny($admin, $customerResource);
       return $this ;
    }
}

and here is my plugin :

<?php

class Dagho_Controller_Plugin_Acl extends Zend_Controller_Plugin_Abstract {

    public function preDispatch(Zend_Controller_Request_Abstract $request) {
        $module = $request->getModuleName();
        $controller = $request->getControllerName();
        $action = $request->getActionName();
        $doctrineAuth = new Dagho_Auth_Doctrine();
        $logged = $doctrineAuth->checklogin();
        $identity = $doctrineAuth->getIdentity();
        Zend_Registry::set("identity", $identity);
        if ($logged && $identity["role"] !== "anonymous") {
            /// user had an identity  let's check the ACL
            $acl = new Dagho_Acl_Main();
            $isAllowed = $acl->isAllowed($identity["role"], $module);
            if (!$isAllowed) {
                return $request->setModuleName("acl")->setControllerName("index")
                        ->setActionName("denied")->setDispatched(true);
            } else {
                /// user has identity and he is allowed to access it
                return;
            }
        } elseif ($logged === false || ($logged && $identity["role"] === "anonymous" )) {
            //// user not logged on > login.php or its his first visit
            $identity = $doctrineAuth->getStorage()->write(array('name' => 'anonymous', 'role' => "anonymous",));
            Zend_Registry::set("identity", $identity);
            return $request->setModuleName("acl")->setControllerName("index")
                    ->setActionName("login")->setDispatched(true);
        } else {
            return $request->setModuleName("acl")->setControllerName("index")
                    ->setActionName("denied")->setDispatched(true);
        }
        parent::preDispatch($request);
    }

}
Aminopyrine answered 6/3, 2011 at 14:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.