Zend Framework——权限控制与认证

Zend Framework Acl与Auth——权限控制与认证

Created with Raphaël 2.1.2 认证开始 登录 发送用户名,密码及数据库连接 校验工作 结果处理 认证结束

步骤
1.实例化Zend_Auth
2.创建适配器
3.执行Zend_Auth类中的getCode方法,根据返回结果执行不同方案

Zend_Acl
官方用法:
新建资源:$someResource = new Zend_Acl_Resource('someResource'),获取资源名getResourceId()
官方给了一个接口:Zend_Acl_Resource_Interface,可以任意拓展
基于特殊resource的查询将自动从resource的等级结构中搜索分配给祖先rResources的规则, 它允许简单的规则继承。一个 resource 可以从唯一的一个父 resource 继承,而这个父 resource 也有它自己的父 resource,等等。Zend_Acl 也支持基于 resources 的权限(例如:”create”, “read”, “update”, “delete”), 所以开发者可以根据 resource 分配影响全部或者特殊权限的规则到一个或多个资源。
新建角色:$someRole = new Zend_Acl_Role('someRole'),获取资源名getRoleId();官方给了一个接口:Zend_Acl_Role_Interface,可以任意拓展,在 Zend_Acl, 一个 role 可以从一个或多个 role 继承,这就是在 role 中支持规则的继承。
例 2.1. 角色之间的多重继承
下面的代码定义了三个基本角色 - “guest”, “member”, 和 “admin” - 其它角色可以从它们继承。接着,创建一个”someUser” 角色并从其它三个基本角色继承。 在$parents 数组里这些角色出现的顺序很重要。 必要时,Zend_Acl 不但搜索为被查询的角色 (这里指 “someUser”)定义的访问规则,而且搜索为被查询的角色所继承的角色 (这里指 “guest”, “member”, and “admin”)定义的访问规则:

$acl = new Zend_Acl();

$acl->addRole(new Zend_Acl_Role('guest'))
    ->addRole(new Zend_Acl_Role('member'))
    ->addRole(new Zend_Acl_Role('admin'));

$parents = array('guest', 'member', 'admin');
$acl->addRole(new Zend_Acl_Role('someUser'), $parents);

$acl->add(new Zend_Acl_Resource('someResource'));

$acl->deny('guest', 'someResource');
$acl->allow('member', 'someResource');

echo $acl->isAllowed('someUser', 'someResource') ? 'allowed' : 'denied';

因为没有明确地为 “someUser”和”someResource” 定义规则, 所以Zend_Acl 必须搜索可能为”someUser”所继承的角色定义的规则。 首先,”admin”角色被访问,没有给它定义访问规则。 接着,”member”角色被访问,Zend_Acl发现有个规则允许”member” 访问”someResource”。

如果Zend_Acl打算继续检查为父角色所定义的规则,然而, 它将发现”guest” 被拒绝访问”someResource” 。 这带来了模棱两可的情形, “someUser”即被允许又被禁止访问”someResource”,因为它从不同的父角色继承了冲突的规则。

Zend_Acl 解决了这个模棱两可的问题,当它发现第一个可用的规则时,就完成了查询。 对于这个案例,因为”member”角色先于”guest” 角色被检查,这个例子将打印”allowed”。
注意
当为一个角色指定多重父(角色)时,请记住,对于一个授权查询的可用规则,最后列出的父(角色)是首先被搜索的。
注意
除非开发者指明一个”allow” 规则,Zend_Acl 禁止任何 role 对任何 resource 的任何访问权限。
2.1.3. 创建访问控制列表(ACL)
$acl = new Zend_Acl();
2.1.4. 注册角色(Role)

$acl = new Zend_Acl();

// 用 Zend_Acl_Role 把组添加到 Role 注册表
// Guest 不继承访问控制
$roleGuest = new Zend_Acl_Role('guest');
$acl->addRole($roleGuest);

// Staff 从 guest 继承
$acl->addRole(new Zend_Acl_Role('staff'), $roleGuest);

/* 
另外, 上面的也可这样来写:
$acl->addRole(new Zend_Acl_Role('staff'), 'guest');
*/

// Editor 从 staff 继承
$acl->addRole(new Zend_Acl_Role('editor'), 'staff');

// Administrator 不继承访问控制
$acl->addRole(new Zend_Acl_Role('administrator'));

2.1.5. 定义访问控制

$acl = new Zend_Acl();

$roleGuest = new Zend_Acl_Role('guest');
$acl->addRole($roleGuest);
$acl->addRole(new Zend_Acl_Role('staff'), $roleGuest);
$acl->addRole(new Zend_Acl_Role('editor'), 'staff');
$acl->addRole(new Zend_Acl_Role('administrator'));

// Guest 只可以浏览内容
$acl->allow($roleGuest, null, 'view');

/* 
另外, 上面也可写为:
$acl->allow('guest', null, 'view');
*/

// Staff 从 guest 继承浏览权限,但也要另外的权限
$acl->allow('staff', null, array('edit', 'submit', 'revise'));

// Editor 从 Staff 继承 view, edit, submit 和 revise 权限
// 但也要另外的权限
$acl->allow('editor', null, array('publish', 'archive', 'delete'));

// Administrator 不需要继承任何权限,它拥有所有的权限
$acl->allow('administrator');

2.1.6. 查询 ACL

echo $acl->isAllowed('guest', null, 'view') ?
     "allowed" : "denied";
// allowed
$acl->allow('marketing',
            array('newsletter', 'latest'),
            array('publish', 'archive'));

2.2.2. 除去访问控制

$acl->removeAllow('marketing',
                  'newsletter',
                  array('publish', 'archive'));

$acl->removeDeny('staff', 'latest', 'revise');

ACL 的对象可以用 PHP 中的 serialize() 函数来序列化,并且结果可以存在开发者所期望的任何地方,例如文件、数据库、或缓存机构。
2.3.2. 使用声明(Assert)来编写条件性的 ACL 规则

class CleanIPAssertion implements Zend_Acl_Assert_Interface
{
    public function assert(Zend_Acl $acl,
                           Zend_Acl_Role_Interface $role = null,
                           Zend_Acl_Resource_Interface $resource = null,
                           $privilege = null)                           
    {
        return $this->_isCleanIP($_SERVER['REMOTE_ADDR']);
    }

    protected function _isCleanIP($ip)
    {
        // ...
    }
}}
$acl = new Zend_Acl();
$acl->allow(null, null, null, new CleanIPAssertion());

你也许注意到我们在这个范例里没有定义任何特定的 resources, 这简单地表示这些规则适用于所有 resources。

Zend_Auth

Zend_Auth类无法使用new或clone实例化对象,只能使用getInstance()来实例化对象,这是单例模式——即当前环境中Auth只能存在一个实例所决定的。

3.1.1. 适配器(Adapter)

class MyAuthAdapter implements Zend_Auth_Adapter_Interface
{
    /**
     * 为 authentication 函数 设置username 和 password 变量
     * @return void(空)
     */
    public function __construct($username, $password)
    {
        // ...
    }

    /**
     * 执行身份验证尝试
     *
     * @throws Zend_Auth_Adapter_Exception If authentication cannot 
     *                                     be performed
     * @return Zend_Auth_Result
     */
    public function authenticate()
    {
        // ...
    }
}

下面四个方法提供了一组基本的用户面临的通用Zend_Auth适配器结果的操作:
isValid() - 返回 true 当且仅当结果表示一个成功的认证尝试
getCode() - 返回一个 Zend_Auth_Result 常量标识符用来决定认证失败的类型或者是否认证成功。这个可以用于开发者希望区别若干认证结果类型的情形,例如,这允许开发者维护详细的认证结果统计。尽管开发这被鼓励去考虑提供这样详细的原因给用户的风险,替而代之使用一般的认证失败信息,这个功能的其它用法是由于可用性的原因提供专用的,定制的信息给用户。更多的信息,参见下面的注释。

getIdentity() - 返回认证尝试的身份

getMessages() - 返回关于认证尝试失败的数组
Zend_Auth_Result::SUCCESS
Zend_Auth_Result::FAILURE
Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND
Zend_Auth_Result::FAILURE_IDENTITY_AMBIGUOUS
Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID
Zend_Auth_Result::FAILURE_UNCATEGORIZED

// inside of AuthController / loginAction
$result = $this->_auth->authenticate($adapter);

switch ($result->getCode()) {

    case Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND:
        /** 身份不存在 **/
        break;

    case Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID:
        /** 凭证无效 **/
        break;

    case Zend_Auth_Result::SUCCESS:
        /** 认真成功 **/
        break;

    default:
        /** 其他失败 **/
        break;
}

3.1.3.1. 在PHP Session 中的默认保存(Persistence)
认证成功后,Zend_Auth默认使用Zend_Session中的Zend_Auth_Storage_Session保存用户数据;也可以通过实现Zend_Auth_Storage_Interface自定义一个对象。
Zend_Auth_Storage_Session

//方法1
$namespace=new Zend_Auth_Storage_Session('someNamespace')
$authNamespace->user = "myusername";

//方法2
$namespace = Zend_Auth::getInstance() -> setStorage(new Zend_Auth_Storage_Session('someNamespace')); 
$someNamespace = $namespace -> getNamespace();//等同于 $someNamespace = $auth -> getNamespace()
$_SESSION[$someNamespace]['user'] = "myusername";//所属用户组

然后,Zend_Auth::authenticate()通过把认证结果放入持久存储中来保存身份。

$namespace = Zend_Auth::getInstance()//单例模式
                     -> getStorage() 
                     -> getNamespace();
$_SESSION[$namespace]['role']     = $result['group_id'];//所属用户组
$_SESSION[$namespace]['userInfo'] = $result;
$_SESSION[$namespace]['userInfo']['lastLoginTime'] = $result['login_time'];
$_SESSION[$namespace]['userInfo']['lastLoginIp']   = $result['login_ip'];           
//$_SESSION[$namespace]['userInfo']['password']   = $result['password'];//密码很重要,不要写到session中

例 3.1. 修改 Session 名字空间
Zend_Auth_Storage_Session使用’Zend_Auth’的seesion名字空间。
$auth->setStorage(); $_SESSION['Zend_Auth']['role']
通过给Zend_Auth_Storage_Session的构造器传递不同的值,这个名字空间可以被替换,并且这个值被从内部传递给Zend_Session_Namespace的构造器。
$auth->setStorage(new Zend_Auth_Storage_Session('someNamespace'));
$_SESSION['someNamespace']['role']
这应该发生在认证尝试之前,因为Zend_Auth::authenticate()执行身份的自动存储。

// 实例化
$auth = Zend_Auth::getInstance();

// 用 'someNamespace' 替换 'Zend_Auth'
$auth->setStorage(new Zend_Auth_Storage_Session('someNamespace'));

/**
 * @todo 设置适配器, $authAdapter
 */

// 进行身份验证成功,保存结果并储存身份信息
$result = $auth->authenticate($authAdapter);

例 3.2. 使用定制存储类
class MyStorage implements Zend_Auth_Storage_Interface
为了使用这个定制的存储类,在认证查询被尝试前,Zend_Auth::setStorage()被调用:

// Instruct Zend_Auth to use the custom storage class
Zend_Auth::getInstance()->setStorage(new MyStorage());

/**
 * @todo 设置适配器, $authAdapter
 */

// 进行身份验证成功,保存结果并储存身份信息
$result = Zend_Auth::getInstance()->authenticate($authAdapter);

3.1.4. 使用Zend_Auth
非直接地,通过Zend_Auth::authenticate()

// 实例化
require_once 'Zend/Auth.php';
$auth = Zend_Auth::getInstance();

// 设置适配器
$authAdapter = new MyAuthAdapter($username, $password);

// 尝试认证,储存信息
$result = $auth->authenticate($authAdapter);

if (!$result->isValid()) {
    // 认证失败,返回原因
    foreach ($result->getMessages() as $message) {
        echo "$message\n";
    }
} else {
    // 认证成功,储存信息,官方自动写入?
}

一旦在一个请求里的认证被尝试,如上面的例子,检查一个成功的被认证的身份是否存在就是一个简单的匹配:

$auth = Zend_Auth::getInstance();
if ($auth->hasIdentity()) {
    // Identity exists; get it
    $identity = $auth->getIdentity();
}

从持久存储空间出去一个身份,可简单地使用clearIdentity()方法。这将被典型地用作“logout”操作。

Zend_Auth::getInstance()->clearIdentity();

如果官方提供的永久存储不合适的话,可以直接使用适配器类。

// 实例化
$authAdapter = new MyAuthAdapter($username, $password);

// 尝试认证,存储身份信息
$result = $authAdapter->authenticate();

if (!$result->isValid()) {
    // 认证失败,返回原因
    foreach ($result->getMessages() as $message) {
        echo "$message\n";
    }
} else {
    // 认证成功,需要自己储存身份信息
}

3.2. 数据库表认证
3.2.1. 简介
Zend_Auth_Adapter_DbTable可以连接数据库进行认证,需要与数据库绑定。其它可用的配置选项包括:

tableName: 数据库表名。

identityColumn: 数据库表的列的名称,用来表示身份。身份列必须包含唯一的值,例如用户名或者e-mail地址。

credentialColumn: 数据库表的列的名称,用来表示证书。在一个简单的身份和密码认证scheme下,证书的值对应为密码。

credentialTreatment: 在许多情况下,密码和其他敏感数据是加密的(encrypted, hashed, encoded, obscured,salted 或者通过以下函数或算法来加工)。通过指定参数化的字串来使用这个方法,例如’MD5(?)’ 或者 ‘PASSWORD(?)’,开发者可以在输入证书数据时使用任意的SQL。因为这些函数对其下面的RDBMS是专用的, 请查看数据库手册来确保你所用的数据库的函数的可用性。

例 3.3. 基本用法

// 创建一个 in-memory SQLite 数据库连接
$dbAdapter = new Zend_Db_Adapter_Pdo_Sqlite(array('dbname' => 
                                                  ':memory:'));
// 1用构造器参数来配置实例...
$authAdapter = new Zend_Auth_Adapter_DbTable(
    $dbAdapter,
    'users',
    'username',
    'password'
);

// 2用构造器参数来配置实例...
$authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);

$authAdapter
    ->setTableName('users')
    ->setIdentityColumn('username')
    ->setCredentialColumn('password')
;
// 设置输入的证书的值(例如,从登陆的表单)
$authAdapter
    ->setIdentity('my_username')
    ->setCredential('my_password')
;

// 执行认证查询,并保存结果
$result = $authAdapter->authenticate();
// 输出身份
echo $result->getIdentity() . "\n\n";

// 输出结果行
print_r($authAdapter->getResultRowObject());

/* Output:
my_username

Array
(
    [id] => 1
    [username] => my_username
    [password] => my_password
    [real_name] => My Real Name
)
*/

3.2.2. 高级使用:保存一个 DbTable 结果对象

// authenticate with Zend_Auth_Adapter_DbTable
$result = $this->_auth->authenticate($adapter);

if ($result->isValid()) {
    // 保存 identity 为对象,username 和 real_name 被返回
    $storage = $this->_auth->getStorage();
    $storage->write($adapter->getResultRowObject(array(
        'username',
        'real_name',
    )));

    // 保存 identity 为对象,password 被忽略
    $storage->write($adapter->getResultRowObject(
        null,
        'password'
    ));

    /* ... */

} else {

    /* ... */

}

Zend_Auth_Adapter_DbTable 有内建的机制可以用来利用添加另外的认证时的检查来解决一些普通的用户问题。

// 帐户的状态字段值不等于"已泄露"
$adapter = new Zend_Auth_Adapter_DbTable(
    $db,
    'users',
    'username',
    'password',
    'MD5(?) AND status != "compromised"'
);

// 帐户的有效字段值等于"TRUE"
$adapter = new Zend_Auth_Adapter_DbTable(
    $db,
    'users',
    'username',
    'password',
    'MD5(?) AND active = "TRUE"'
);

另外一个场景是免疫机制的实现。
因此我们需要修改表来存储免疫的字符串:

$sqlAlter = "ALTER TABLE [users] "
          . "ADD COLUMN [password_salt] "
          . "AFTER [password]";

$dbAdapter->query($sqlAlter);

这里是在注册时给每个用户生成免疫字符串的简单的方法:

for ($i = 0; $i < 50; $i++)
{
    $dynamicSalt .= chr(rand(33, 126));
}

构造适配器:

$adapter = new Zend_Auth_Adapter_DbTable(
    $db,
    'users',
    'username',
    'password',
    "MD5(CONCAT('" 
    . Zend_Registry::get('staticSalt') 
    . "', ?, password_salt))"
);

实例:
解释:

Zend_Auth_Adapter_Interface中提供了一个接口,我们需要自己去实现

代码如下:

<?php
require_once 'Zend/Auth/Adapter/Interface.php';
class Auth implements Zend_Auth_Adapter_Interface{
    private $_useraccount;
    private $_password;
    private $_db;
    /**
     * 构造函数 设置用户名和密码 数据连接对象   
     * 
     * @return void      
     */
    public function __construct($useraccount,$password,$db){   
        $this->_useraccount = $useraccount;
        $this->_password      = $password;
        $this->_db             = $db; 
    }

    /**     
     * 进行认证  
     * @throws Zend_Auth_Adapter_Exception    
     * @return Zend_Auth_Result
     * 
     */
    public function authenticate()
    {
        //默认情况下是认证失败
        $authResult = array(
            'code'     => Zend_Auth_Result::FAILURE,//详参:Zend_Auth_Result
            'identity' => '',
            'info' => array()
           );

           //获得登录用户信息
        $result = $this->_getAccountData();

        if(isset($result)&&!empty($result)) {//认证成功,则将用户信息存储到session中
            $authResult = array(
                'code'     => Zend_Auth_Result::SUCCESS,
                'identity' => $result['name'],
                'info'     => array('status'=>$result['status'])
            );
            //角色存储  个人缓存空间
            $namespace = Zend_Auth::getInstance()//单例模式
                                 -> getStorage() 
                                 -> getNamespace();
            $_SESSION[$namespace]['role']     = $result['group_id'];//所属用户组
            $_SESSION[$namespace]['userInfo'] = $result;
            $_SESSION[$namespace]['userInfo']['lastLoginTime'] = $result['login_time'];
            $_SESSION[$namespace]['userInfo']['lastLoginIp']   = $result['login_ip'];           
//            $_SESSION[$namespace]['userInfo']['password']   = $result['password'];//密码是很重要的,不要写到session中
        }

        return new Zend_Auth_Result($authResult['code'], $authResult['identity'], $authResult['info']);
    }
    /**
     * 用户密码加密
     * @param $pwd  原始密码
     * @return string  加密后的密码字符串
     * 
     */
    static public function encryptionType($pwd=null) {
        $pwd = md5($pwd);
        return $pwd;
    }
    /**
     * 获得用户数据结构
     * 
     * @todo 整理密码的公共类
     */
    private function _getAccountData(){
        $resArr = array();
        $sysUserObj = Base_Dao_Factory::getObject('Admin_Models_User');
        //先登录普通会员帐号
        $data = array(
            'login_name' => $this->_useraccount,
            'login_pwd'  => $this->encryptionType($this->_password)
        );
        $result = $sysUserObj->login($data);
        //判断是否有数据,是则赋值
        if ($result) {
            if (!empty($result[0])) {
                $resArr = $result[0];
            }
        }
        return $resArr;
    }
}

解释:在authenticate方法的实现代码中,return一个Zend_Auth_Result对象实例,而查看Zend_Auth_Result的源代码,知道实例化的时候需要传入三个参数:

@param int $code 身份认证的结果(如:Zend_Auth_Result::SUCCESS)

@param mixed $identity 用于身份认证的标示符(如:登录名(张三))

@param array $messages 认证失败的原因数组

而一旦认证成功,则将信息存储到session变量中。

 $auth=Zend_Auth::getInstance();        
 if ($auth->hasIdentity()){
       echo $auth->getIdentity();    //输出:张三
       $auth->clearIdentity();       //清除身份
 }
 echo $auth->getIdentity();          //NULL
 var_dump($auth->getStorage());     //Zend_Auth_Storage_Session对象

Acl
在action被Zend_Controller_Dispatcher派发之前,会先调用Zend_Controller_Plugin_Abstract类中的preDispatch()方法,因此我们可以继承Zend_Controller_Plugin_Abstract类,在子类中的preDispatch方法中进行权限判断。

代码如下:

Verify.php

<?php
require_once 'Zend/Controller/Plugin/Abstract.php';
class Verify extends Zend_Controller_Plugin_Abstract
{
    /**
     * 访问控制列表对象
     * @var object
     */
    protected $_acl;
    /**
     * 登录的用户名
     * @var string 
     */
    protected $_loginname;

    /**
     * 构造函数
     * 初始化访问控制列表
     * @param Acl $acl
     * @todo 未登录的时候,$this -> _loginname是为空的
     */
    public function __construct($acl)
    {
        $this -> _acl = $acl;
        require_once('Zend/Auth.php');
        $this -> _loginname = Zend_Auth::getInstance()->getIdentity();//eg:张三
    }

    /**
     * 重写父类的preDispatch方法
     * 
     * @param Zend_Controller_Request_Abstract $request
     */
    public function preDispatch(Zend_Controller_Request_Abstract $request)
    {
        //请求信息
        $module     = $request -> module;                //模块
        $controller = $request -> controller;            //请求的控制器
        $action     = $request -> action;                //请求的action

        $resource = ucfirst(strtolower($controller));    //资源:一个限制访问的对象
        $action   = strtolower($action);                
        $role     = $this->_acl->getRole();                //角色:一个可以发出请求去访问Resource的对象

        //判断是否拥有资源
        if(!($this -> _acl -> has($resource))) {
            $resource = null;
        }

//        $this->_acl->removeAllow($role,$resource);        //可以针对某个role移除权限
        //判断当前用户是有权限执行某个请求
        if(!($this -> _acl -> isAllowed($role, $resource, $action))) {
            if (!$this -> _loginname) {//未登陆的情况
                $module     = 'admin';
                $controller = 'login';
                $action     = 'view';
            }else {                      //没有权限的情况
                echo "<script>
                        $.messager.alert('提醒','您没有操作权限', 'warning');
                    </script>";
                exit();
            }
        }
//        else {    //认证成功
//            
//        }
        $request -> setModuleName($module);
        $request -> setControllerName($controller);
        $request -> setActionName($action);
    }
}

解释:思路其实很简单,首先获取当前用户的角色(或超管或访客),然后使用isAllowed方法来判断请求者在整个 web 应用里是否拥有执行功能的许可,从而执行不同的流程控制。

但是,这里涉及到几个问题:

①preDispatch方法在哪里调用呢

②Verify类在哪里进行实例化

③访问控制列表(acl)如何定义

解答:

第一个问题:preDispatch在Zend_Controller_Action的dispatch方法中被调用(502行左右),该方法先于postDispatch被调用。

第二个问题:在入口文件index.php中进行实例化

acl=newAcl();//Acl a c l = n e w A c l ( ) ; / / 自 定 义 的 A c l 类 fc = Zend_Controller_Front::getInstance();//取得Zend_Controller_Front类实例
fc>registerPlugin(newVerify( f c − > r e g i s t e r P l u g i n ( n e w V e r i f y ( acl));
以上代码片段的$acl = new Acl()也正是第三个问题将要回答的

第三个问题:关于访问控制列表的定义,及如何添加角色,添加资源,可以仔细看看官方手册,讲得很详细

http://framework.zend.com/manual/1.12/zh/zend.acl.introduction.html

Zend_Acl中的几个方法:

allow:增加一条“允许”规则到acl列表

如:$acl->allow(‘guest’, null, ‘view’);//允许游客具有访问的权限

deny:增加一条“禁止”规则到acl列表

如:$acl->deny(‘guest’, null, ‘view’);//禁止游客具有访问的权限

isAllowed:判断某个角色(role)是否有权访问某个资源(resource)

remove:删除某个资源及其子资源

removeAll:从ACL中删除所有的资源

removeAllow:从ACL中删除某个role有权访问的资源

removeDeny:从ACL中删除某个role禁止访问的资源

removeRole:从ACL中删除某个角色role

addRole:添加一个唯一的角色到ACL注册表中

hasRole:判断某个角色role是否已注册过

getRole:返回当前用户角色

getRoles:返回一个注册角色的数组

getResources:返回注册过的资源数组

在项目中,我们可以写一个Acl类,继承自Zend_Acl,而角色,资源等的添加定义都可以在自定义类中去实现

好比如这样:

Acl.php(自定义)

<?php
require_once('Zend/Acl.php');
/**
 * 角色权限控制
 * 
 */
class Acl extends Zend_Acl
{
    public function __construct()
    {
        $role = $this -> getRole();                    //获取用户角色
        if ($role=='guest') {                        //访客角色
            $roleGuest=new Zend_Acl_Role('guest');    //创建角色guest
            $this->addRole($roleGuest);                //将角色添加到role注册表
            $this -> add(new Zend_Acl_Resource('Login'));
            $this -> add(new Zend_Acl_Resource('User'));
            $this -> allow('guest', null, array('login'));    //允许访客到登录界面
            $this -> allow('guest', null, Array('showuserbydep'));//允许guest根据部门获取用户
        }else {                                    //登录用户的权限
            //如果该角色不存在,则添加到Role注册表中,否则后面的代码会报错
            //eg:Fatal error: Uncaught exception 'Zend_Acl_Role_Registry_Exception' with message 'Role 'admin' not found'
            if (!$this->hasRole($role)) {
                $this -> addRole(new Zend_Acl_Role($role));
            }

            //登录的用户都有的权限
            $this -> add(new Zend_Acl_Resource('Index'));
            $this -> add(new Zend_Acl_Resource('Dep'));
            $this -> add(new Zend_Acl_Resource('Login'));
            $this -> add(new Zend_Acl_Resource('Order'));
            $this -> add(new Zend_Acl_Resource('Shopping'));
            $this -> add(new Zend_Acl_Resource('User'));
            $this -> add(new Zend_Acl_Resource('Authgroup'));

            //第三个参数不写,默认具有访问整个控制器的权限
            $this -> allow($role,'Index',Array('index'));
            $this -> allow($role,'Login',Array('index','login','admin','top','left','view','welcome','logout'));
            $this -> allow($role,'Order',Array('orderhistory'));
            $this -> allow($role,'Shopping',Array('showmenu','uploadimage','showshop','showfood'));
            $this -> allow($role,'User','index');
            $this -> allow($role,'Dep',Array('showdep'));
            $this -> allow($role,'Authgroup','index');

            $rolePurview = $this -> getRolePurview($role);//角色的权限
            //判断权限数据格式是否正确
            if(!is_Array($rolePurview)){
                echo '权限数据格式有错误!';exit();
            }else{
                foreach ($rolePurview as $controller => $actionArray){
                    //controller资源
                    $resource = ucfirst($controller);

                    //判断是否拥有资源
                    if(!$this -> has($resource)){//没有资源
                        $this -> add(new Zend_Acl_Resource($resource));//增加资源
                    }

                    //判断资源数据格式是否正确
                    if(!is_Array($actionArray) || empty($actionArray)){
                        echo '资源数据格式有错误!';exit();
                    }else{
                        foreach ($actionArray as $action){
                            $this -> allow($role, $resource, $action);//允许角色访问资源
                        }
                    }
                }
            }
        }
    }

    /**
     * 获取用户的角色名
     * @return string
     */
    public function getRole()
    {
        $ns = Zend_Auth::getInstance() -> getStorage() -> getNamespace();

        //有session信息
        if(isset($_SESSION[$ns])) {//有登录
            if(isset($_SESSION[$ns]['role'])){//判断有没有登录用户的角色信息
                $role = $_SESSION[$ns]['role'];
            }else {
                $role = 'guest';
            }
        }else {
            $role = 'guest';
        }
        return $role;
    }

    /**
     * 获得登录用户的数据数据
     *
     */
    public function getUserInfo()
    {
        $namespace = Zend_Auth::getInstance() -> getStorage() -> getNamespace();
        //用户认证失败则返回false
        if(isset($_SESSION[$namespace]['userInfo'])) {
            return $_SESSION[$namespace]['userInfo'];
        }else{
            return false;
        }
    }
    /**
     * 获得权限数据 
     * @return Array   成功返回
     * @return Array   失败返回
     * @todo 只有成功登陆页面的情况下才有数据
     */
    public function getUserPermission()
    {
        $namespace = Zend_Auth::getInstance() -> getStorage() -> getNamespace();
        if(isset($_SESSION[$namespace]['resourcesPurview'])){
            return $_SESSION[$namespace]['resourcesPurview'];
        }else{
            return false;
        }
    }    
    /**
     * 根据角色获取权限(获取指定角色的访问控制列表)
     *
     * @param Array $role
     * @return unknown
     */
    public function getRolePurview($role)
    {
        if(!is_string($role)){
            return false;
        }else {
            $rolePurview = $this -> getAllPurview();
            return $rolePurview[$role];
        }
    }    
    /**
     * 获取所有角色的权限(访问控制列表)
     *
     * @return Array
     */
    public function getAllPurview()
    {
        $rolePurview = Array();
        //判断缓存是否存在,有则从缓存中取,否则从数据库中取
        if (!empty($_SESSION['allRolePurviews'])) {
            $rolePurview = $_SESSION['allRolePurviews'];
        }else{
            $roleDao = Base_Dao_Factory::getObject('Admin_Models_Authgroup');
            $result  = $roleDao -> getAllGroup(Array('id', 'group_purview'));

            if(!empty($result)){
                foreach ($result as $key => $value){
                    $purview[$value['id']] = Zend_Json::decode($value['group_purview']);
                }
            }
            $rolePurview = $purview;
            $_SESSION['allRolePurviews'] = $purview;
        }
        return $rolePurview;
    }    
}

解释:自定义的Acl类中,我们首先要判断当前登录用户是访客还是系统用户,从而针对不同的用户角色给予不同的权限。

通过allow()我们可以很容易的针对不同的角色给予不同的权限控制。

注:对于出“访客”外的其他所有用户角色,都有一些默认的权限

现在我抛出一个问题:系统用户肯定有多个分组(比如:超级管理员和普通用户的权限定然不一样)那如何针对不同的用户组分配不同的权限呢?

这个容易,可以将不同组的权限存到数据库中,要用到的时候,根据不同的用户角色查得其所有的访问权限,在循环遍历下,通过allow将角色权限添加到acl中即可,也就是以上的代码片段:
我是将权限以json的格式形式存入数据库中的,而在服务器上创建一个Permission.php文件,以二维数组的形式进行保存,每当需要添加权限时,得手动编辑该文件,而要给不同的用户组分配不同的权限的时候,采用复选框的方式进行勾选即可。
Zend_Acl_Role 接口

interface Zend_Acl_Role_Interface
{
    /**
     * Returns the string identifier of the Role
     *
     * @return string
     */
    public function getRoleId();
}

Zend_Acl_Role

class Zend_Acl_Role implements Zend_Acl_Role_Interface
{
    /**
     * Unique id of Role
     *
     * @var string
     */
    protected $_roleId;

    /**
     * Sets the Role identifier
     *
     * @param  string $roleId
     */
    public function __construct($roleId)
    {
        $this->_roleId = (string) $roleId;
    }

    /**
     * Defined by Zend_Acl_Role_Interface; returns the Role identifier
     *
     * @return string
     */
    public function getRoleId()
    {
        return $this->_roleId;
    }

    /**
     * Defined by Zend_Acl_Role_Interface; returns the Role identifier
     * Proxies to getRoleId()
     *
     * @return string
     */
    public function __toString()
    {
        return $this->getRoleId();
    }
}

Zend_Acl_Resource 接口

interface Zend_Acl_Resource_Interface
{
    /**
     * Returns the string identifier of the Resource
     *
     * @return string
     */
    public function getResourceId();
}

Zend_Acl_Resource

class Zend_Acl_Resource implements Zend_Acl_Resource_Interface
{
    /**
     * Unique id of Resource
     *
     * @var string
     */
    protected $_resourceId;

    /**
     * Sets the Resource identifier
     *
     * @param  string $resourceId
     */
    public function __construct($resourceId)
    {
        $this->_resourceId = (string) $resourceId;
    }

    /**
     * Defined by Zend_Acl_Resource_Interface; returns the Resource identifier
     *
     * @return string
     */
    public function getResourceId()
    {
        return $this->_resourceId;
    }

    /**
     * Defined by Zend_Acl_Resource_Interface; returns the Resource identifier
     * Proxies to getResourceId()
     *
     * @return string
     */
    public function __toString()
    {
        return $this->getResourceId();
    }
}

Zend_Acl_Role_Registry

class Zend_Acl_Role_Registry
{
    /**
     * Internal Role registry data storage
     *
     * @var array
     */
    protected $_roles = array();

    /**
     * Adds a Role having an identifier unique to the registry
     *
     * The $parents parameter may be a reference to, or the string identifier for,
     * a Role existing in the registry, or $parents may be passed as an array of
     * these - mixing string identifiers and objects is ok - to indicate the Roles
     * from which the newly added Role will directly inherit.
     *
     * In order to resolve potential ambiguities with conflicting rules inherited
     * from different parents, the most recently added parent takes precedence over
     * parents that were previously added. In other words, the first parent added
     * will have the least priority, and the last parent added will have the
     * highest priority.
     *
     * @param  Zend_Acl_Role_Interface              $role
     * @param  Zend_Acl_Role_Interface|string|array $parents
     * @throws Zend_Acl_Role_Registry_Exception
     * @return Zend_Acl_Role_Registry Provides a fluent interface
     */
    public function add(Zend_Acl_Role_Interface $role, $parents = null)
    {
        $roleId = $role->getRoleId();

        if ($this->has($roleId)) {
            /**
             * @see Zend_Acl_Role_Registry_Exception
             */
            require_once 'Zend/Acl/Role/Registry/Exception.php';
            throw new Zend_Acl_Role_Registry_Exception("Role id '$roleId' already exists in the registry");
        }

        $roleParents = array();

        if (null !== $parents) {
            if (!is_array($parents)) {
                $parents = array($parents);
            }
            /**
             * @see Zend_Acl_Role_Registry_Exception
             */
            require_once 'Zend/Acl/Role/Registry/Exception.php';
            foreach ($parents as $parent) {
                try {
                    if ($parent instanceof Zend_Acl_Role_Interface) {
                        $roleParentId = $parent->getRoleId();
                    } else {
                        $roleParentId = $parent;
                    }
                    $roleParent = $this->get($roleParentId);
                } catch (Zend_Acl_Role_Registry_Exception $e) {
                    throw new Zend_Acl_Role_Registry_Exception("Parent Role id '$roleParentId' does not exist", 0, $e);
                }
                $roleParents[$roleParentId] = $roleParent;
                $this->_roles[$roleParentId]['children'][$roleId] = $role;
            }
        }

        $this->_roles[$roleId] = array(
            'instance' => $role,
            'parents'  => $roleParents,
            'children' => array()
            );

        return $this;
    }

    /**
     * Returns the identified Role
     *
     * The $role parameter can either be a Role or a Role identifier.
     *
     * @param  Zend_Acl_Role_Interface|string $role
     * @throws Zend_Acl_Role_Registry_Exception
     * @return Zend_Acl_Role_Interface
     */
    public function get($role)
    {
        if ($role instanceof Zend_Acl_Role_Interface) {
            $roleId = $role->getRoleId();
        } else {
            $roleId = (string) $role;
        }

        if (!$this->has($role)) {
            /**
             * @see Zend_Acl_Role_Registry_Exception
             */
            require_once 'Zend/Acl/Role/Registry/Exception.php';
            throw new Zend_Acl_Role_Registry_Exception("Role '$roleId' not found");
        }

        return $this->_roles[$roleId]['instance'];
    }

    /**
     * Returns true if and only if the Role exists in the registry
     *
     * The $role parameter can either be a Role or a Role identifier.
     *
     * @param  Zend_Acl_Role_Interface|string $role
     * @return boolean
     */
    public function has($role)
    {
        if ($role instanceof Zend_Acl_Role_Interface) {
            $roleId = $role->getRoleId();
        } else {
            $roleId = (string) $role;
        }

        return isset($this->_roles[$roleId]);
    }

    /**
     * Returns an array of an existing Role's parents
     *
     * The array keys are the identifiers of the parent Roles, and the values are
     * the parent Role instances. The parent Roles are ordered in this array by
     * ascending priority. The highest priority parent Role, last in the array,
     * corresponds with the parent Role most recently added.
     *
     * If the Role does not have any parents, then an empty array is returned.
     *
     * @param  Zend_Acl_Role_Interface|string $role
     * @uses   Zend_Acl_Role_Registry::get()
     * @return array
     */
    public function getParents($role)
    {
        $roleId = $this->get($role)->getRoleId();

        return $this->_roles[$roleId]['parents'];
    }

    /**
     * Returns true if and only if $role inherits from $inherit
     *
     * Both parameters may be either a Role or a Role identifier. If
     * $onlyParents is true, then $role must inherit directly from
     * $inherit in order to return true. By default, this method looks
     * through the entire inheritance DAG to determine whether $role
     * inherits from $inherit through its ancestor Roles.
     *
     * @param  Zend_Acl_Role_Interface|string $role
     * @param  Zend_Acl_Role_Interface|string $inherit
     * @param  boolean                        $onlyParents
     * @throws Zend_Acl_Role_Registry_Exception
     * @return boolean
     */
    public function inherits($role, $inherit, $onlyParents = false)
    {
        /**
         * @see Zend_Acl_Role_Registry_Exception
         */
        require_once 'Zend/Acl/Role/Registry/Exception.php';
        try {
            $roleId     = $this->get($role)->getRoleId();
            $inheritId = $this->get($inherit)->getRoleId();
        } catch (Zend_Acl_Role_Registry_Exception $e) {
            throw new Zend_Acl_Role_Registry_Exception($e->getMessage(), $e->getCode(), $e);
        }

        $inherits = isset($this->_roles[$roleId]['parents'][$inheritId]);

        if ($inherits || $onlyParents) {
            return $inherits;
        }

        foreach ($this->_roles[$roleId]['parents'] as $parentId => $parent) {
            if ($this->inherits($parentId, $inheritId)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Removes the Role from the registry
     *
     * The $role parameter can either be a Role or a Role identifier.
     *
     * @param  Zend_Acl_Role_Interface|string $role
     * @throws Zend_Acl_Role_Registry_Exception
     * @return Zend_Acl_Role_Registry Provides a fluent interface
     */
    public function remove($role)
    {
        /**
         * @see Zend_Acl_Role_Registry_Exception
         */
        require_once 'Zend/Acl/Role/Registry/Exception.php';
        try {
            $roleId = $this->get($role)->getRoleId();
        } catch (Zend_Acl_Role_Registry_Exception $e) {
            throw new Zend_Acl_Role_Registry_Exception($e->getMessage(), $e->getCode(), $e);
        }

        foreach ($this->_roles[$roleId]['children'] as $childId => $child) {
            unset($this->_roles[$childId]['parents'][$roleId]);
        }
        foreach ($this->_roles[$roleId]['parents'] as $parentId => $parent) {
            unset($this->_roles[$parentId]['children'][$roleId]);
        }

        unset($this->_roles[$roleId]);

        return $this;
    }

    /**
     * Removes all Roles from the registry
     *
     * @return Zend_Acl_Role_Registry Provides a fluent interface
     */
    public function removeAll()
    {
        $this->_roles = array();

        return $this;
    }

    public function getRoles()
    {
        return $this->_roles;
    }

}

Zend_Acl

<?php



/**
 * @see Zend_Acl_Resource_Interface
 */
require_once 'Zend/Acl/Resource/Interface.php';


/**
 * @see Zend_Acl_Role_Registry
 */
require_once 'Zend/Acl/Role/Registry.php';


/**
 * @see Zend_Acl_Assert_Interface
 */
require_once 'Zend/Acl/Assert/Interface.php';


/**
 * @see Zend_Acl_Role
 */
require_once 'Zend/Acl/Role.php';


/**
 * @see Zend_Acl_Resource
 */
require_once 'Zend/Acl/Resource.php';


/**
 * @category   Zend
 * @package    Zend_Acl
 * @copyright  Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 */
class Zend_Acl
{
    /**
     * Rule type: allow
     */
    const TYPE_ALLOW = 'TYPE_ALLOW';

    /**
     * Rule type: deny
     */
    const TYPE_DENY  = 'TYPE_DENY';

    /**
     * Rule operation: add
     */
    const OP_ADD = 'OP_ADD';

    /**
     * Rule operation: remove
     */
    const OP_REMOVE = 'OP_REMOVE';

    /**
     * Role registry
     *
     * @var Zend_Acl_Role_Registry
     */
    protected $_roleRegistry = null;

    /**
     * Resource tree
     *
     * @var array
     */
    protected $_resources = array();

    /**
     * @var Zend_Acl_Role_Interface
     */
    protected $_isAllowedRole     = null;

    /**
     * @var Zend_Acl_Resource_Interface
     */
    protected $_isAllowedResource = null;

    /**
     * @var String
     */
    protected $_isAllowedPrivilege = null;

    /**
     * ACL rules; whitelist (deny everything to all) by default
     *
     * @var array
     */
    protected $_rules = array(
        'allResources' => array(
            'allRoles' => array(
                'allPrivileges' => array(
                    'type'   => self::TYPE_DENY,
                    'assert' => null
                    ),
                'byPrivilegeId' => array()
                ),
            'byRoleId' => array()
            ),
        'byResourceId' => array()
        );

    /**
     * Adds a Role having an identifier unique to the registry
     *
     * The $parents parameter may be a reference to, or the string identifier for,
     * a Role existing in the registry, or $parents may be passed as an array of
     * these - mixing string identifiers and objects is ok - to indicate the Roles
     * from which the newly added Role will directly inherit.
     *
     * In order to resolve potential ambiguities with conflicting rules inherited
     * from different parents, the most recently added parent takes precedence over
     * parents that were previously added. In other words, the first parent added
     * will have the least priority, and the last parent added will have the
     * highest priority.
     *
     * @param  Zend_Acl_Role_Interface|string       $role
     * @param  Zend_Acl_Role_Interface|string|array $parents
     * @uses   Zend_Acl_Role_Registry::add()
     * @return Zend_Acl Provides a fluent interface
     */
    public function addRole($role, $parents = null)
    {
        if (is_string($role)) {
            $role = new Zend_Acl_Role($role);
        }

        if (!$role instanceof Zend_Acl_Role_Interface) {
            require_once 'Zend/Acl/Exception.php';
            throw new Zend_Acl_Exception('addRole() expects $role to be of type Zend_Acl_Role_Interface');
        }


        $this->_getRoleRegistry()->add($role, $parents);

        return $this;
    }

    /**
     * Returns the identified Role
     *
     * The $role parameter can either be a Role or Role identifier.
     *
     * @param  Zend_Acl_Role_Interface|string $role
     * @uses   Zend_Acl_Role_Registry::get()
     * @return Zend_Acl_Role_Interface
     */
    public function getRole($role)
    {
        return $this->_getRoleRegistry()->get($role);
    }

    /**
     * Returns true if and only if the Role exists in the registry
     *
     * The $role parameter can either be a Role or a Role identifier.
     *
     * @param  Zend_Acl_Role_Interface|string $role
     * @uses   Zend_Acl_Role_Registry::has()
     * @return boolean
     */
    public function hasRole($role)
    {
        return $this->_getRoleRegistry()->has($role);
    }

    /**
     * Returns true if and only if $role inherits from $inherit
     *
     * Both parameters may be either a Role or a Role identifier. If
     * $onlyParents is true, then $role must inherit directly from
     * $inherit in order to return true. By default, this method looks
     * through the entire inheritance DAG to determine whether $role
     * inherits from $inherit through its ancestor Roles.
     *
     * @param  Zend_Acl_Role_Interface|string $role
     * @param  Zend_Acl_Role_Interface|string $inherit
     * @param  boolean                        $onlyParents
     * @uses   Zend_Acl_Role_Registry::inherits()
     * @return boolean
     */
    public function inheritsRole($role, $inherit, $onlyParents = false)
    {
        return $this->_getRoleRegistry()->inherits($role, $inherit, $onlyParents);
    }

    /**
     * Removes the Role from the registry
     *
     * The $role parameter can either be a Role or a Role identifier.
     *
     * @param  Zend_Acl_Role_Interface|string $role
     * @uses   Zend_Acl_Role_Registry::remove()
     * @return Zend_Acl Provides a fluent interface
     */
    public function removeRole($role)
    {
        $this->_getRoleRegistry()->remove($role);

        if ($role instanceof Zend_Acl_Role_Interface) {
            $roleId = $role->getRoleId();
        } else {
            $roleId = $role;
        }

        foreach ($this->_rules['allResources']['byRoleId'] as $roleIdCurrent => $rules) {
            if ($roleId === $roleIdCurrent) {
                unset($this->_rules['allResources']['byRoleId'][$roleIdCurrent]);
            }
        }
        foreach ($this->_rules['byResourceId'] as $resourceIdCurrent => $visitor) {
            if (array_key_exists('byRoleId', $visitor)) {
                foreach ($visitor['byRoleId'] as $roleIdCurrent => $rules) {
                    if ($roleId === $roleIdCurrent) {
                        unset($this->_rules['byResourceId'][$resourceIdCurrent]['byRoleId'][$roleIdCurrent]);
                    }
                }
            }
        }

        return $this;
    }

    /**
     * Removes all Roles from the registry
     *
     * @uses   Zend_Acl_Role_Registry::removeAll()
     * @return Zend_Acl Provides a fluent interface
     */
    public function removeRoleAll()
    {
        $this->_getRoleRegistry()->removeAll();

        foreach ($this->_rules['allResources']['byRoleId'] as $roleIdCurrent => $rules) {
            unset($this->_rules['allResources']['byRoleId'][$roleIdCurrent]);
        }
        foreach ($this->_rules['byResourceId'] as $resourceIdCurrent => $visitor) {
            foreach ($visitor['byRoleId'] as $roleIdCurrent => $rules) {
                unset($this->_rules['byResourceId'][$resourceIdCurrent]['byRoleId'][$roleIdCurrent]);
            }
        }

        return $this;
    }

    /**
     * Adds a Resource having an identifier unique to the ACL
     *
     * The $parent parameter may be a reference to, or the string identifier for,
     * the existing Resource from which the newly added Resource will inherit.
     *
     * @param  Zend_Acl_Resource_Interface|string $resource
     * @param  Zend_Acl_Resource_Interface|string $parent
     * @throws Zend_Acl_Exception
     * @return Zend_Acl Provides a fluent interface
     */
    public function addResource($resource, $parent = null)
    {
        if (is_string($resource)) {
            $resource = new Zend_Acl_Resource($resource);
        }

        if (!$resource instanceof Zend_Acl_Resource_Interface) {
            require_once 'Zend/Acl/Exception.php';
            throw new Zend_Acl_Exception('addResource() expects $resource to be of type Zend_Acl_Resource_Interface');
        }

        $resourceId = $resource->getResourceId();

        if ($this->has($resourceId)) {
            require_once 'Zend/Acl/Exception.php';
            throw new Zend_Acl_Exception("Resource id '$resourceId' already exists in the ACL");
        }

        $resourceParent = null;

        if (null !== $parent) {
            try {
                if ($parent instanceof Zend_Acl_Resource_Interface) {
                    $resourceParentId = $parent->getResourceId();
                } else {
                    $resourceParentId = $parent;
                }
                $resourceParent = $this->get($resourceParentId);
            } catch (Zend_Acl_Exception $e) {
                require_once 'Zend/Acl/Exception.php';
                throw new Zend_Acl_Exception("Parent Resource id '$resourceParentId' does not exist", 0, $e);
            }
            $this->_resources[$resourceParentId]['children'][$resourceId] = $resource;
        }

        $this->_resources[$resourceId] = array(
            'instance' => $resource,
            'parent'   => $resourceParent,
            'children' => array()
            );

        return $this;
    }

    /**
     * Adds a Resource having an identifier unique to the ACL
     *
     * The $parent parameter may be a reference to, or the string identifier for,
     * the existing Resource from which the newly added Resource will inherit.
     *
     * @deprecated in version 1.9.1 and will be available till 2.0.  New code
     *             should use addResource() instead.
     *
     * @param  Zend_Acl_Resource_Interface        $resource
     * @param  Zend_Acl_Resource_Interface|string $parent
     * @throws Zend_Acl_Exception
     * @return Zend_Acl Provides a fluent interface
     */
    public function add(Zend_Acl_Resource_Interface $resource, $parent = null)
    {
        return $this->addResource($resource, $parent);
    }

    /**
     * Returns the identified Resource
     *
     * The $resource parameter can either be a Resource or a Resource identifier.
     *
     * @param  Zend_Acl_Resource_Interface|string $resource
     * @throws Zend_Acl_Exception
     * @return Zend_Acl_Resource_Interface
     */
    public function get($resource)
    {
        if ($resource instanceof Zend_Acl_Resource_Interface) {
            $resourceId = $resource->getResourceId();
        } else {
            $resourceId = (string) $resource;
        }

        if (!$this->has($resource)) {
            require_once 'Zend/Acl/Exception.php';
            throw new Zend_Acl_Exception("Resource '$resourceId' not found");
        }

        return $this->_resources[$resourceId]['instance'];
    }

    /**
     * Returns true if and only if the Resource exists in the ACL
     *
     * The $resource parameter can either be a Resource or a Resource identifier.
     *
     * @param  Zend_Acl_Resource_Interface|string $resource
     * @return boolean
     */
    public function has($resource)
    {
        if ($resource instanceof Zend_Acl_Resource_Interface) {
            $resourceId = $resource->getResourceId();
        } else {
            $resourceId = (string) $resource;
        }

        return isset($this->_resources[$resourceId]);
    }

    /**
     * Returns true if and only if $resource inherits from $inherit
     *
     * Both parameters may be either a Resource or a Resource identifier. If
     * $onlyParent is true, then $resource must inherit directly from
     * $inherit in order to return true. By default, this method looks
     * through the entire inheritance tree to determine whether $resource
     * inherits from $inherit through its ancestor Resources.
     *
     * @param  Zend_Acl_Resource_Interface|string $resource
     * @param  Zend_Acl_Resource_Interface|string $inherit
     * @param  boolean                            $onlyParent
     * @throws Zend_Acl_Resource_Registry_Exception
     * @return boolean
     */
    public function inherits($resource, $inherit, $onlyParent = false)
    {
        try {
            $resourceId     = $this->get($resource)->getResourceId();
            $inheritId = $this->get($inherit)->getResourceId();
        } catch (Zend_Acl_Exception $e) {
            require_once 'Zend/Acl/Exception.php';
            throw new Zend_Acl_Exception($e->getMessage(), $e->getCode(), $e);
        }

        if (null !== $this->_resources[$resourceId]['parent']) {
            $parentId = $this->_resources[$resourceId]['parent']->getResourceId();
            if ($inheritId === $parentId) {
                return true;
            } else if ($onlyParent) {
                return false;
            }
        } else {
            return false;
        }

        while (null !== $this->_resources[$parentId]['parent']) {
            $parentId = $this->_resources[$parentId]['parent']->getResourceId();
            if ($inheritId === $parentId) {
                return true;
            }
        }

        return false;
    }

    /**
     * Removes a Resource and all of its children
     *
     * The $resource parameter can either be a Resource or a Resource identifier.
     *
     * @param  Zend_Acl_Resource_Interface|string $resource
     * @throws Zend_Acl_Exception
     * @return Zend_Acl Provides a fluent interface
     */
    public function remove($resource)
    {
        try {
            $resourceId = $this->get($resource)->getResourceId();
        } catch (Zend_Acl_Exception $e) {
            require_once 'Zend/Acl/Exception.php';
            throw new Zend_Acl_Exception($e->getMessage(), $e->getCode(), $e);
        }

        $resourcesRemoved = array($resourceId);
        if (null !== ($resourceParent = $this->_resources[$resourceId]['parent'])) {
            unset($this->_resources[$resourceParent->getResourceId()]['children'][$resourceId]);
        }
        foreach ($this->_resources[$resourceId]['children'] as $childId => $child) {
            $this->remove($childId);
            $resourcesRemoved[] = $childId;
        }

        foreach ($resourcesRemoved as $resourceIdRemoved) {
            foreach ($this->_rules['byResourceId'] as $resourceIdCurrent => $rules) {
                if ($resourceIdRemoved === $resourceIdCurrent) {
                    unset($this->_rules['byResourceId'][$resourceIdCurrent]);
                }
            }
        }

        unset($this->_resources[$resourceId]);

        return $this;
    }

    /**
     * Removes all Resources
     *
     * @return Zend_Acl Provides a fluent interface
     */
    public function removeAll()
    {
        foreach ($this->_resources as $resourceId => $resource) {
            foreach ($this->_rules['byResourceId'] as $resourceIdCurrent => $rules) {
                if ($resourceId === $resourceIdCurrent) {
                    unset($this->_rules['byResourceId'][$resourceIdCurrent]);
                }
            }
        }

        $this->_resources = array();

        return $this;
    }

    /**
     * Adds an "allow" rule to the ACL
     *
     * @param  Zend_Acl_Role_Interface|string|array     $roles
     * @param  Zend_Acl_Resource_Interface|string|array $resources
     * @param  string|array                             $privileges
     * @param  Zend_Acl_Assert_Interface                $assert
     * @uses   Zend_Acl::setRule()
     * @return Zend_Acl Provides a fluent interface
     */
    public function allow($roles = null, $resources = null, $privileges = null, Zend_Acl_Assert_Interface $assert = null)
    {
        return $this->setRule(self::OP_ADD, self::TYPE_ALLOW, $roles, $resources, $privileges, $assert);
    }

    /**
     * Adds a "deny" rule to the ACL
     *
     * @param  Zend_Acl_Role_Interface|string|array     $roles
     * @param  Zend_Acl_Resource_Interface|string|array $resources
     * @param  string|array                             $privileges
     * @param  Zend_Acl_Assert_Interface                $assert
     * @uses   Zend_Acl::setRule()
     * @return Zend_Acl Provides a fluent interface
     */
    public function deny($roles = null, $resources = null, $privileges = null, Zend_Acl_Assert_Interface $assert = null)
    {
        return $this->setRule(self::OP_ADD, self::TYPE_DENY, $roles, $resources, $privileges, $assert);
    }

    /**
     * Removes "allow" permissions from the ACL
     *
     * @param  Zend_Acl_Role_Interface|string|array     $roles
     * @param  Zend_Acl_Resource_Interface|string|array $resources
     * @param  string|array                             $privileges
     * @uses   Zend_Acl::setRule()
     * @return Zend_Acl Provides a fluent interface
     */
    public function removeAllow($roles = null, $resources = null, $privileges = null)
    {
        return $this->setRule(self::OP_REMOVE, self::TYPE_ALLOW, $roles, $resources, $privileges);
    }

    /**
     * Removes "deny" restrictions from the ACL
     *
     * @param  Zend_Acl_Role_Interface|string|array     $roles
     * @param  Zend_Acl_Resource_Interface|string|array $resources
     * @param  string|array                             $privileges
     * @uses   Zend_Acl::setRule()
     * @return Zend_Acl Provides a fluent interface
     */
    public function removeDeny($roles = null, $resources = null, $privileges = null)
    {
        return $this->setRule(self::OP_REMOVE, self::TYPE_DENY, $roles, $resources, $privileges);
    }

    /**
     * Performs operations on ACL rules
     *
     * The $operation parameter may be either OP_ADD or OP_REMOVE, depending on whether the
     * user wants to add or remove a rule, respectively:
     *
     * OP_ADD specifics:
     *
     *      A rule is added that would allow one or more Roles access to [certain $privileges
     *      upon] the specified Resource(s).
     *
     * OP_REMOVE specifics:
     *
     *      The rule is removed only in the context of the given Roles, Resources, and privileges.
     *      Existing rules to which the remove operation does not apply would remain in the
     *      ACL.
     *
     * The $type parameter may be either TYPE_ALLOW or TYPE_DENY, depending on whether the
     * rule is intended to allow or deny permission, respectively.
     *
     * The $roles and $resources parameters may be references to, or the string identifiers for,
     * existing Resources/Roles, or they may be passed as arrays of these - mixing string identifiers
     * and objects is ok - to indicate the Resources and Roles to which the rule applies. If either
     * $roles or $resources is null, then the rule applies to all Roles or all Resources, respectively.
     * Both may be null in order to work with the default rule of the ACL.
     *
     * The $privileges parameter may be used to further specify that the rule applies only
     * to certain privileges upon the Resource(s) in question. This may be specified to be a single
     * privilege with a string, and multiple privileges may be specified as an array of strings.
     *
     * If $assert is provided, then its assert() method must return true in order for
     * the rule to apply. If $assert is provided with $roles, $resources, and $privileges all
     * equal to null, then a rule having a type of:
     *
     *      TYPE_ALLOW will imply a type of TYPE_DENY, and
     *
     *      TYPE_DENY will imply a type of TYPE_ALLOW
     *
     * when the rule's assertion fails. This is because the ACL needs to provide expected
     * behavior when an assertion upon the default ACL rule fails.
     *
     * @param  string                                   $operation
     * @param  string                                   $type
     * @param  Zend_Acl_Role_Interface|string|array     $roles
     * @param  Zend_Acl_Resource_Interface|string|array $resources
     * @param  string|array                             $privileges
     * @param  Zend_Acl_Assert_Interface                $assert
     * @throws Zend_Acl_Exception
     * @uses   Zend_Acl_Role_Registry::get()
     * @uses   Zend_Acl::get()
     * @return Zend_Acl Provides a fluent interface
     */
    public function setRule($operation, $type, $roles = null, $resources = null, $privileges = null,
                            Zend_Acl_Assert_Interface $assert = null)
    {
        // ensure that the rule type is valid; normalize input to uppercase
        $type = strtoupper($type);
        if (self::TYPE_ALLOW !== $type && self::TYPE_DENY !== $type) {
            require_once 'Zend/Acl/Exception.php';
            throw new Zend_Acl_Exception("Unsupported rule type; must be either '" . self::TYPE_ALLOW . "' or '"
                                       . self::TYPE_DENY . "'");
        }

        // ensure that all specified Roles exist; normalize input to array of Role objects or null
        if (!is_array($roles)) {
            $roles = array($roles);
        } else if (0 === count($roles)) {
            $roles = array(null);
        }
        $rolesTemp = $roles;
        $roles = array();
        foreach ($rolesTemp as $role) {
            if (null !== $role) {
                $roles[] = $this->_getRoleRegistry()->get($role);
            } else {
                $roles[] = null;
            }
        }
        unset($rolesTemp);

        // ensure that all specified Resources exist; normalize input to array of Resource objects or null
        if ($resources !== null) {
            if (!is_array($resources)) {
                $resources = array($resources);
            } else if (0 === count($resources)) {
                $resources = array(null);
            }
            $resourcesTemp = $resources;
            $resources = array();
            foreach ($resourcesTemp as $resource) {
                if (null !== $resource) {
                    $resources[] = $this->get($resource);
                } else {
                    $resources[] = null;
                }
            }
            unset($resourcesTemp, $resource);
        } else {
            $allResources = array(); // this might be used later if resource iteration is required
            foreach ($this->_resources as $rTarget) {
                $allResources[] = $rTarget['instance'];
            }
            unset($rTarget);
        }

        // normalize privileges to array
        if (null === $privileges) {
            $privileges = array();
        } else if (!is_array($privileges)) {
            $privileges = array($privileges);
        }

        switch ($operation) {

            // add to the rules
            case self::OP_ADD:
                if ($resources !== null) {
                    // this block will iterate the provided resources
                    foreach ($resources as $resource) {
                        foreach ($roles as $role) {
                            $rules =& $this->_getRules($resource, $role, true);
                            if (0 === count($privileges)) {
                                $rules['allPrivileges']['type']   = $type;
                                $rules['allPrivileges']['assert'] = $assert;
                                if (!isset($rules['byPrivilegeId'])) {
                                    $rules['byPrivilegeId'] = array();
                                }
                            } else {
                                foreach ($privileges as $privilege) {
                                    $rules['byPrivilegeId'][$privilege]['type']   = $type;
                                    $rules['byPrivilegeId'][$privilege]['assert'] = $assert;
                                }
                            }
                        }
                    }
                } else {
                    // this block will apply to all resources in a global rule
                    foreach ($roles as $role) {
                        $rules =& $this->_getRules(null, $role, true);
                        if (0 === count($privileges)) {
                            $rules['allPrivileges']['type']   = $type;
                            $rules['allPrivileges']['assert'] = $assert;
                        } else {
                            foreach ($privileges as $privilege) {
                                $rules['byPrivilegeId'][$privilege]['type']   = $type;
                                $rules['byPrivilegeId'][$privilege]['assert'] = $assert;
                            }
                        }
                    }
                }
                break;

            // remove from the rules
            case self::OP_REMOVE:
                if ($resources !== null) {
                    // this block will iterate the provided resources
                    foreach ($resources as $resource) {
                        foreach ($roles as $role) {
                            $rules =& $this->_getRules($resource, $role);
                            if (null === $rules) {
                                continue;
                            }
                            if (0 === count($privileges)) {
                                if (null === $resource && null === $role) {
                                    if ($type === $rules['allPrivileges']['type']) {
                                        $rules = array(
                                            'allPrivileges' => array(
                                                'type'   => self::TYPE_DENY,
                                                'assert' => null
                                                ),
                                            'byPrivilegeId' => array()
                                            );
                                    }
                                    continue;
                                }

                                if (isset($rules['allPrivileges']['type']) &&
                                    $type === $rules['allPrivileges']['type'])
                                {
                                    unset($rules['allPrivileges']);
                                }
                            } else {
                                foreach ($privileges as $privilege) {
                                    if (isset($rules['byPrivilegeId'][$privilege]) &&
                                        $type === $rules['byPrivilegeId'][$privilege]['type'])
                                    {
                                        unset($rules['byPrivilegeId'][$privilege]);
                                    }
                                }
                            }
                        }
                    }
                } else {
                    // this block will apply to all resources in a global rule
                    foreach ($roles as $role) {
                        /**
                         * since null (all resources) was passed to this setRule() call, we need
                         * clean up all the rules for the global allResources, as well as the indivually
                         * set resources (per privilege as well)
                         */
                        foreach (array_merge(array(null), $allResources) as $resource) {
                            $rules =& $this->_getRules($resource, $role, true);
                            if (null === $rules) {
                                continue;
                            }
                            if (0 === count($privileges)) {
                                if (null === $role) {
                                    if ($type === $rules['allPrivileges']['type']) {
                                        $rules = array(
                                            'allPrivileges' => array(
                                                'type'   => self::TYPE_DENY,
                                                'assert' => null
                                                ),
                                            'byPrivilegeId' => array()
                                            );
                                    }
                                    continue;
                                }

                                if (isset($rules['allPrivileges']['type']) && $type === $rules['allPrivileges']['type']) {
                                    unset($rules['allPrivileges']);
                                }
                            } else {
                                foreach ($privileges as $privilege) {
                                    if (isset($rules['byPrivilegeId'][$privilege]) &&
                                        $type === $rules['byPrivilegeId'][$privilege]['type'])
                                    {
                                        unset($rules['byPrivilegeId'][$privilege]);
                                    }
                                }
                            }
                        }
                    }
                }
                break;

            default:
                require_once 'Zend/Acl/Exception.php';
                throw new Zend_Acl_Exception("Unsupported operation; must be either '" . self::OP_ADD . "' or '"
                                           . self::OP_REMOVE . "'");
        }

        return $this;
    }

    /**
     * Returns true if and only if the Role has access to the Resource
     *
     * The $role and $resource parameters may be references to, or the string identifiers for,
     * an existing Resource and Role combination.
     *
     * If either $role or $resource is null, then the query applies to all Roles or all Resources,
     * respectively. Both may be null to query whether the ACL has a "blacklist" rule
     * (allow everything to all). By default, Zend_Acl creates a "whitelist" rule (deny
     * everything to all), and this method would return false unless this default has
     * been overridden (i.e., by executing $acl->allow()).
     *
     * If a $privilege is not provided, then this method returns false if and only if the
     * Role is denied access to at least one privilege upon the Resource. In other words, this
     * method returns true if and only if the Role is allowed all privileges on the Resource.
     *
     * This method checks Role inheritance using a depth-first traversal of the Role registry.
     * The highest priority parent (i.e., the parent most recently added) is checked first,
     * and its respective parents are checked similarly before the lower-priority parents of
     * the Role are checked.
     *
     * @param  Zend_Acl_Role_Interface|string     $role
     * @param  Zend_Acl_Resource_Interface|string $resource
     * @param  string                             $privilege
     * @uses   Zend_Acl::get()
     * @uses   Zend_Acl_Role_Registry::get()
     * @return boolean
     */
    public function isAllowed($role = null, $resource = null, $privilege = null)
    {
        // reset role & resource to null
        $this->_isAllowedRole = null;
        $this->_isAllowedResource = null;
        $this->_isAllowedPrivilege = null;

        if (null !== $role) {
            // keep track of originally called role
            $this->_isAllowedRole = $role;
            $role = $this->_getRoleRegistry()->get($role);
            if (!$this->_isAllowedRole instanceof Zend_Acl_Role_Interface) {
                $this->_isAllowedRole = $role;
            }
        }

        if (null !== $resource) {
            // keep track of originally called resource
            $this->_isAllowedResource = $resource;
            $resource = $this->get($resource);
            if (!$this->_isAllowedResource instanceof Zend_Acl_Resource_Interface) {
                $this->_isAllowedResource = $resource;
            }
        }

        if (null === $privilege) {
            // query on all privileges
            do {
                // depth-first search on $role if it is not 'allRoles' pseudo-parent
                if (null !== $role && null !== ($result = $this->_roleDFSAllPrivileges($role, $resource, $privilege))) {
                    return $result;
                }

                // look for rule on 'allRoles' psuedo-parent
                if (null !== ($rules = $this->_getRules($resource, null))) {
                    foreach ($rules['byPrivilegeId'] as $privilege => $rule) {
                        if (self::TYPE_DENY === ($ruleTypeOnePrivilege = $this->_getRuleType($resource, null, $privilege))) {
                            return false;
                        }
                    }
                    if (null !== ($ruleTypeAllPrivileges = $this->_getRuleType($resource, null, null))) {
                        return self::TYPE_ALLOW === $ruleTypeAllPrivileges;
                    }
                }

                // try next Resource
                $resource = $this->_resources[$resource->getResourceId()]['parent'];

            } while (true); // loop terminates at 'allResources' pseudo-parent
        } else {
            $this->_isAllowedPrivilege = $privilege;
            // query on one privilege
            do {
                // depth-first search on $role if it is not 'allRoles' pseudo-parent
                if (null !== $role && null !== ($result = $this->_roleDFSOnePrivilege($role, $resource, $privilege))) {
                    return $result;
                }

                // look for rule on 'allRoles' pseudo-parent
                if (null !== ($ruleType = $this->_getRuleType($resource, null, $privilege))) {
                    return self::TYPE_ALLOW === $ruleType;
                } else if (null !== ($ruleTypeAllPrivileges = $this->_getRuleType($resource, null, null))) {
                    return self::TYPE_ALLOW === $ruleTypeAllPrivileges;
                }

                // try next Resource
                $resource = $this->_resources[$resource->getResourceId()]['parent'];

            } while (true); // loop terminates at 'allResources' pseudo-parent
        }
    }

    /**
     * Returns the Role registry for this ACL
     *
     * If no Role registry has been created yet, a new default Role registry
     * is created and returned.
     *
     * @return Zend_Acl_Role_Registry
     */
    protected function _getRoleRegistry()
    {
        if (null === $this->_roleRegistry) {
            $this->_roleRegistry = new Zend_Acl_Role_Registry();
        }
        return $this->_roleRegistry;
    }

    /**
     * Performs a depth-first search of the Role DAG, starting at $role, in order to find a rule
     * allowing/denying $role access to all privileges upon $resource
     *
     * This method returns true if a rule is found and allows access. If a rule exists and denies access,
     * then this method returns false. If no applicable rule is found, then this method returns null.
     *
     * @param  Zend_Acl_Role_Interface     $role
     * @param  Zend_Acl_Resource_Interface $resource
     * @return boolean|null
     */
    protected function _roleDFSAllPrivileges(Zend_Acl_Role_Interface $role, Zend_Acl_Resource_Interface $resource = null)
    {
        $dfs = array(
            'visited' => array(),
            'stack'   => array()
            );

        if (null !== ($result = $this->_roleDFSVisitAllPrivileges($role, $resource, $dfs))) {
            return $result;
        }

        while (null !== ($role = array_pop($dfs['stack']))) {
            if (!isset($dfs['visited'][$role->getRoleId()])) {
                if (null !== ($result = $this->_roleDFSVisitAllPrivileges($role, $resource, $dfs))) {
                    return $result;
                }
            }
        }

        return null;
    }

    /**
     * Visits an $role in order to look for a rule allowing/denying $role access to all privileges upon $resource
     *
     * This method returns true if a rule is found and allows access. If a rule exists and denies access,
     * then this method returns false. If no applicable rule is found, then this method returns null.
     *
     * This method is used by the internal depth-first search algorithm and may modify the DFS data structure.
     *
     * @param  Zend_Acl_Role_Interface     $role
     * @param  Zend_Acl_Resource_Interface $resource
     * @param  array                  $dfs
     * @return boolean|null
     * @throws Zend_Acl_Exception
     */
    protected function _roleDFSVisitAllPrivileges(Zend_Acl_Role_Interface $role, Zend_Acl_Resource_Interface $resource = null,
                                                 &$dfs = null)
    {
        if (null === $dfs) {
            /**
             * @see Zend_Acl_Exception
             */
            require_once 'Zend/Acl/Exception.php';
            throw new Zend_Acl_Exception('$dfs parameter may not be null');
        }

        if (null !== ($rules = $this->_getRules($resource, $role))) {
            foreach ($rules['byPrivilegeId'] as $privilege => $rule) {
                if (self::TYPE_DENY === ($ruleTypeOnePrivilege = $this->_getRuleType($resource, $role, $privilege))) {
                    return false;
                }
            }
            if (null !== ($ruleTypeAllPrivileges = $this->_getRuleType($resource, $role, null))) {
                return self::TYPE_ALLOW === $ruleTypeAllPrivileges;
            }
        }

        $dfs['visited'][$role->getRoleId()] = true;
        foreach ($this->_getRoleRegistry()->getParents($role) as $roleParentId => $roleParent) {
            $dfs['stack'][] = $roleParent;
        }

        return null;
    }

    /**
     * Performs a depth-first search of the Role DAG, starting at $role, in order to find a rule
     * allowing/denying $role access to a $privilege upon $resource
     *
     * This method returns true if a rule is found and allows access. If a rule exists and denies access,
     * then this method returns false. If no applicable rule is found, then this method returns null.
     *
     * @param  Zend_Acl_Role_Interface     $role
     * @param  Zend_Acl_Resource_Interface $resource
     * @param  string                      $privilege
     * @return boolean|null
     * @throws Zend_Acl_Exception
     */
    protected function _roleDFSOnePrivilege(Zend_Acl_Role_Interface $role, Zend_Acl_Resource_Interface $resource = null,
                                            $privilege = null)
    {
        if (null === $privilege) {
            /**
             * @see Zend_Acl_Exception
             */
            require_once 'Zend/Acl/Exception.php';
            throw new Zend_Acl_Exception('$privilege parameter may not be null');
        }

        $dfs = array(
            'visited' => array(),
            'stack'   => array()
            );

        if (null !== ($result = $this->_roleDFSVisitOnePrivilege($role, $resource, $privilege, $dfs))) {
            return $result;
        }

        while (null !== ($role = array_pop($dfs['stack']))) {
            if (!isset($dfs['visited'][$role->getRoleId()])) {
                if (null !== ($result = $this->_roleDFSVisitOnePrivilege($role, $resource, $privilege, $dfs))) {
                    return $result;
                }
            }
        }

        return null;
    }

    /**
     * Visits an $role in order to look for a rule allowing/denying $role access to a $privilege upon $resource
     *
     * This method returns true if a rule is found and allows access. If a rule exists and denies access,
     * then this method returns false. If no applicable rule is found, then this method returns null.
     *
     * This method is used by the internal depth-first search algorithm and may modify the DFS data structure.
     *
     * @param  Zend_Acl_Role_Interface     $role
     * @param  Zend_Acl_Resource_Interface $resource
     * @param  string                      $privilege
     * @param  array                       $dfs
     * @return boolean|null
     * @throws Zend_Acl_Exception
     */
    protected function _roleDFSVisitOnePrivilege(Zend_Acl_Role_Interface $role, Zend_Acl_Resource_Interface $resource = null,
                                                $privilege = null, &$dfs = null)
    {
        if (null === $privilege) {
            /**
             * @see Zend_Acl_Exception
             */
            require_once 'Zend/Acl/Exception.php';
            throw new Zend_Acl_Exception('$privilege parameter may not be null');
        }

        if (null === $dfs) {
            /**
             * @see Zend_Acl_Exception
             */
            require_once 'Zend/Acl/Exception.php';
            throw new Zend_Acl_Exception('$dfs parameter may not be null');
        }

        if (null !== ($ruleTypeOnePrivilege = $this->_getRuleType($resource, $role, $privilege))) {
            return self::TYPE_ALLOW === $ruleTypeOnePrivilege;
        } else if (null !== ($ruleTypeAllPrivileges = $this->_getRuleType($resource, $role, null))) {
            return self::TYPE_ALLOW === $ruleTypeAllPrivileges;
        }

        $dfs['visited'][$role->getRoleId()] = true;
        foreach ($this->_getRoleRegistry()->getParents($role) as $roleParentId => $roleParent) {
            $dfs['stack'][] = $roleParent;
        }

        return null;
    }

    /**
     * Returns the rule type associated with the specified Resource, Role, and privilege
     * combination.
     *
     * If a rule does not exist or its attached assertion fails, which means that
     * the rule is not applicable, then this method returns null. Otherwise, the
     * rule type applies and is returned as either TYPE_ALLOW or TYPE_DENY.
     *
     * If $resource or $role is null, then this means that the rule must apply to
     * all Resources or Roles, respectively.
     *
     * If $privilege is null, then the rule must apply to all privileges.
     *
     * If all three parameters are null, then the default ACL rule type is returned,
     * based on whether its assertion method passes.
     *
     * @param  Zend_Acl_Resource_Interface $resource
     * @param  Zend_Acl_Role_Interface     $role
     * @param  string                      $privilege
     * @return string|null
     */
    protected function _getRuleType(Zend_Acl_Resource_Interface $resource = null, Zend_Acl_Role_Interface $role = null,
                                    $privilege = null)
    {
        // get the rules for the $resource and $role
        if (null === ($rules = $this->_getRules($resource, $role))) {
            return null;
        }

        // follow $privilege
        if (null === $privilege) {
            if (isset($rules['allPrivileges'])) {
                $rule = $rules['allPrivileges'];
            } else {
                return null;
            }
        } else if (!isset($rules['byPrivilegeId'][$privilege])) {
            return null;
        } else {
            $rule = $rules['byPrivilegeId'][$privilege];
        }

        // check assertion first
        if ($rule['assert']) {
            $assertion = $rule['assert'];
            $assertionValue = $assertion->assert(
                $this,
                ($this->_isAllowedRole instanceof Zend_Acl_Role_Interface) ? $this->_isAllowedRole : $role,
                ($this->_isAllowedResource instanceof Zend_Acl_Resource_Interface) ? $this->_isAllowedResource : $resource,
                $this->_isAllowedPrivilege
                );
        }

        if (null === $rule['assert'] || $assertionValue) {
            return $rule['type'];
        } else if (null !== $resource || null !== $role || null !== $privilege) {
            return null;
        } else if (self::TYPE_ALLOW === $rule['type']) {
            return self::TYPE_DENY;
        } else {
            return self::TYPE_ALLOW;
        }
    }

    /**
     * Returns the rules associated with a Resource and a Role, or null if no such rules exist
     *
     * If either $resource or $role is null, this means that the rules returned are for all Resources or all Roles,
     * respectively. Both can be null to return the default rule set for all Resources and all Roles.
     *
     * If the $create parameter is true, then a rule set is first created and then returned to the caller.
     *
     * @param  Zend_Acl_Resource_Interface $resource
     * @param  Zend_Acl_Role_Interface     $role
     * @param  boolean                     $create
     * @return array|null
     */
    protected function &_getRules(Zend_Acl_Resource_Interface $resource = null, Zend_Acl_Role_Interface $role = null,
                                  $create = false)
    {
        // create a reference to null
        $null = null;
        $nullRef =& $null;

        // follow $resource
        do {
            if (null === $resource) {
                $visitor =& $this->_rules['allResources'];
                break;
            }
            $resourceId = $resource->getResourceId();
            if (!isset($this->_rules['byResourceId'][$resourceId])) {
                if (!$create) {
                    return $nullRef;
                }
                $this->_rules['byResourceId'][$resourceId] = array();
            }
            $visitor =& $this->_rules['byResourceId'][$resourceId];
        } while (false);


        // follow $role
        if (null === $role) {
            if (!isset($visitor['allRoles'])) {
                if (!$create) {
                    return $nullRef;
                }
                $visitor['allRoles']['byPrivilegeId'] = array();
            }
            return $visitor['allRoles'];
        }
        $roleId = $role->getRoleId();
        if (!isset($visitor['byRoleId'][$roleId])) {
            if (!$create) {
                return $nullRef;
            }
            $visitor['byRoleId'][$roleId]['byPrivilegeId'] = array();
            $visitor['byRoleId'][$roleId]['allPrivileges'] = array('type' => null, 'assert' => null);
        }
        return $visitor['byRoleId'][$roleId];
    }


    /**
     * @return array of registered roles (Deprecated)
     * @deprecated Deprecated since version 1.10 (December 2009)
     */
    public function getRegisteredRoles()
    {
        trigger_error('The method getRegisteredRoles() was deprecated as of '
                    . 'version 1.0, and may be removed. You\'re encouraged '
                    . 'to use getRoles() instead.');

        return $this->_getRoleRegistry()->getRoles();
    }

    /**
     * Returns an array of registered roles.
     *
     * Note that this method does not return instances of registered roles,
     * but only the role identifiers.
     *
     * @return array of registered roles
     */
    public function getRoles()
    {
        return array_keys($this->_getRoleRegistry()->getRoles());
    }

    /**
     * @return array of registered resources
     */
    public function getResources()
    {
        return array_keys($this->_resources);
    }

}

Zend_Acl_Assert 接口

interface Zend_Acl_Assert_Interface
{
    /**
     * Returns true if and only if the assertion conditions are met
     *
     * This method is passed the ACL, Role, Resource, and privilege to which the authorization query applies. If the
     * $role, $resource, or $privilege parameters are null, it means that the query applies to all Roles, Resources, or
     * privileges, respectively.
     *
     * @param  Zend_Acl                    $acl
     * @param  Zend_Acl_Role_Interface     $role
     * @param  Zend_Acl_Resource_Interface $resource
     * @param  string                      $privilege
     * @return boolean
     */
    public function assert(Zend_Acl $acl, Zend_Acl_Role_Interface $role = null, Zend_Acl_Resource_Interface $resource = null,
                           $privilege = null);
}

Auth
Zend_Auth_Result

class Zend_Auth_Result
{
    /**
     * General Failure
     */
    const FAILURE                        =  0;

    /**
     * Failure due to identity not being found.
     */
    const FAILURE_IDENTITY_NOT_FOUND     = -1;

    /**
     * Failure due to identity being ambiguous.
     */
    const FAILURE_IDENTITY_AMBIGUOUS     = -2;

    /**
     * Failure due to invalid credential being supplied.
     */
    const FAILURE_CREDENTIAL_INVALID     = -3;

    /**
     * Failure due to uncategorized reasons.
     */
    const FAILURE_UNCATEGORIZED          = -4;

    /**
     * Authentication success.
     */
    const SUCCESS                        =  1;

    /**
     * Authentication result code
     *
     * @var int
     */
    protected $_code;

    /**
     * The identity used in the authentication attempt
     *
     * @var mixed
     */
    protected $_identity;

    /**
     * An array of string reasons why the authentication attempt was unsuccessful
     *
     * If authentication was successful, this should be an empty array.
     *
     * @var array
     */
    protected $_messages;

    /**
     * Sets the result code, identity, and failure messages
     *
     * @param int   $code
     * @param mixed $identity
     * @param array $messages
     */
    public function __construct($code, $identity, array $messages = array())
    {
        $code = (int) $code;

        if ($code < self::FAILURE_UNCATEGORIZED) {
            $code = self::FAILURE;
        } elseif ($code > self::SUCCESS ) {
            $code = 1;
        }

        $this->_code     = $code;
        $this->_identity = $identity;
        $this->_messages = $messages;
    }

    /**
     * Returns whether the result represents a successful authentication attempt
     *
     * @return boolean
     */
    public function isValid()
    {
        return ($this->_code > 0) ? true : false;
    }

    /**
     * getCode() - Get the result code for this authentication attempt
     *
     * @return int
     */
    public function getCode()
    {
        return $this->_code;
    }

    /**
     * Returns the identity used in the authentication attempt
     *
     * @return mixed
     */
    public function getIdentity()
    {
        return $this->_identity;
    }

    /**
     * Returns an array of string reasons why the authentication attempt was unsuccessful
     *
     * If authentication was successful, this method returns an empty array.
     *
     * @return array
     */
    public function getMessages()
    {
        return $this->_messages;
    }
}

Zend_Auth_Storage_Interface

interface Zend_Auth_Storage_Interface
{
    /**
     * Returns true if and only if storage is empty
     *
     * @throws Zend_Auth_Storage_Exception If it is impossible to determine whether storage is empty
     * @return boolean
     */
    public function isEmpty();

    /**
     * Returns the contents of storage
     *
     * Behavior is undefined when storage is empty.
     *
     * @throws Zend_Auth_Storage_Exception If reading contents from storage is impossible
     * @return mixed
     */
    public function read();

    /**
     * Writes $contents to storage
     *
     * @param  mixed $contents
     * @throws Zend_Auth_Storage_Exception If writing $contents to storage is impossible
     * @return void
     */
    public function write($contents);

    /**
     * Clears contents from storage
     *
     * @throws Zend_Auth_Storage_Exception If clearing contents from storage is impossible
     * @return void
     */
    public function clear();
}
class Zend_Auth_Storage_NonPersistent implements Zend_Auth_Storage_Interface
{
    /**
     * Holds the actual auth data
     */
    protected $_data;

    /**
     * Returns true if and only if storage is empty
     *
     * @throws Zend_Auth_Storage_Exception If it is impossible to determine whether storage is empty
     * @return boolean
     */
    public function isEmpty()
    {
        return empty($this->_data);
    }

    /**
     * Returns the contents of storage
     * Behavior is undefined when storage is empty.
     *
     * @throws Zend_Auth_Storage_Exception If reading contents from storage is impossible
     * @return mixed
     */
    public function read()
    {
        return $this->_data;
    }

    /**
     * Writes $contents to storage
     *
     * @param  mixed $contents
     * @throws Zend_Auth_Storage_Exception If writing $contents to storage is impossible
     * @return void
     */
    public function write($contents)
    {
        $this->_data = $contents;
    }

    /**
     * Clears contents from storage
     *
     * @throws Zend_Auth_Storage_Exception If clearing contents from storage is impossible
     * @return void
     */
    public function clear()
    {
        $this->_data = null;
    }
}
class Zend_Auth_Storage_Session implements Zend_Auth_Storage_Interface
{
    /**
     * Default session namespace
     */
    const NAMESPACE_DEFAULT = 'Zend_Auth';

    /**
     * Default session object member name
     */
    const MEMBER_DEFAULT = 'storage';

    /**
     * Object to proxy $_SESSION storage
     *
     * @var Zend_Session_Namespace
     */
    protected $_session;

    /**
     * Session namespace
     *
     * @var mixed
     */
    protected $_namespace;

    /**
     * Session object member
     *
     * @var mixed
     */
    protected $_member;

    /**
     * Sets session storage options and initializes session namespace object
     *
     * @param mixed $namespace
     * @param mixed $member
     */
    public function __construct($namespace = self::NAMESPACE_DEFAULT, $member = self::MEMBER_DEFAULT)
    {
        $this->_namespace = $namespace;
        $this->_member    = $member;
        $this->_session   = new Zend_Session_Namespace($this->_namespace);
    }

    /**
     * Returns the session namespace
     *
     * @return string
     */
    public function getNamespace()
    {
        return $this->_namespace;
    }

    /**
     * Returns the name of the session object member
     *
     * @return string
     */
    public function getMember()
    {
        return $this->_member;
    }

    /**
     * Defined by Zend_Auth_Storage_Interface
     *
     * @return boolean
     */
    public function isEmpty()
    {
        return !isset($this->_session->{$this->_member});
    }

    /**
     * Defined by Zend_Auth_Storage_Interface
     *
     * @return mixed
     */
    public function read()
    {
        return $this->_session->{$this->_member};
    }

    /**
     * Defined by Zend_Auth_Storage_Interface
     *
     * @param  mixed $contents
     * @return void
     */
    public function write($contents)
    {
        $this->_session->{$this->_member} = $contents;
    }

    /**
     * Defined by Zend_Auth_Storage_Interface
     *
     * @return void
     */
    public function clear()
    {
        unset($this->_session->{$this->_member});
    }
}
interface Zend_Auth_Adapter_Interface
{
    /**
     * Performs an authentication attempt
     *
     * @throws Zend_Auth_Adapter_Exception If authentication cannot be performed
     * @return Zend_Auth_Result
     */
    public function authenticate();
}

Zend Framework 手册中文版 Zend_Acl
Zend Framework 手册中文版 Zend_Auth
使用Zend_Auth和Zend_Acl进行登录认证及根据用户角色进行权限控制——曾是土木人

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值