天天看點

Zend Framework——權限控制與認證

Zend Framework Acl與Auth——權限控制與認證

步驟

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 = ; $i < ; $i++)
{
    $dynamicSalt .= chr(rand(, ));
}
           

構造擴充卡:

$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[])) {
                $resArr = $result[];
            }
        }
        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對象
           
Zend Framework——權限控制與認證

在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", , $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", , $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 ( === 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 ( === 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 ( === 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 ( === 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 ( === 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 ( === 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                        =  ;

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

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

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

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

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

    /**
     * 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 = ;
        }

        $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 > ) ? 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進行登入認證及根據使用者角色進行權限控制——曾是土木人