第 2 章 Zend_Acl
上一页 |  | 下一页

## 第 2 章 Zend_Acl

## 2.1. 简介

Zend_Acl 提供轻量并灵活的访问控制列表 (ACL,access control list) 功能和权限管理。一般地，应用软件可以利用这样的功能限制某些特定对象来访问特定保护的对象。

在本文档中，

- Resource （资源）是一个限制访问的对象。

- Role （角色）是一个可以发出请求去访问Resource的对象。

简单地说就是：Roles 请求访问 Resources。例如，如果一个人要用汽车，这样，这个人就是发出请求的 Role，而这辆汽车就是 Resource，所以使用这辆车就在控制之中了。

通过规范和访问控制列表（ACL）的使用，应用软件可以控制如何授权给发出请求的对象（Roles）来访问被保护的对象（Resources）。

### 2.1.1. 关于资源(Resource)

在 Zend_Acl 中，创建建一个 Resource 非常简单。Zend_Acl 提供了`Zend_Acl_Resource_Interface` 使开发者创建 Resources 非常容易。为了使Zend_Acl把某个对象当作一个Resource，一个类只需要实现这个只包含了一个方法 `getResourceId()` 的接口。 另外，`Zend_Acl_Resource`是一个包含在 Zend_Acl 里作为一个基本的 Resource 实现的类，开发者可以任意扩展它。

Zend_Acl 提供了一个树结构，它可以添加多个 Resources (或者叫“访问控制下的区域”）。因为 Resources 被存储在这样一个树结构，所以它们可以被组织成从一般（树根）到特殊（树叶）。基于特殊Resource的查询将自动从Resource的等级结构中搜索分配给祖先Resources的规则，它允许简单的规则继承。例如，要把一个缺省的规则应用到一个城市的每个建筑物，就简单地把这个规则分配给这个城市，而不是把规则分配给每个建筑物。然而，有些建筑物也许要求例外的规则，在Zend_Acl里，很容易地通过分配例外规则给每个有这样要求的建筑物来实现。一个 Resource 可以从唯一的一个父 Resource 继承，而这个父 Resource 也有它自己的父 Resource，等等。

Zend_Acl 也支持基于 Resources 的权限（例如："create", "read", "update", "delete"）， 开发者可以根据 Resource 分配影响全部或者特殊权限的规则。

### 2.1.2. 关于角色(Role)

象 Resources 一样，创建一个 Role 也非常简单。 Zend_Acl 提供了 `Zend_Acl_Role_Interface` 使开发者创建 Roles 非常容易。为了使Zend_Acl把某个对象当作一个 Role，一个类只需要实现这个只包含了一个方法 `getRoleId()` 的接口。 另外，`Zend_Acl_Role`是一个包含在Zend_Acl里作为一个基本的 Role 实现的类，开发者可以任意扩展它。

在 Zend_Acl, 一个 Role 可以从一个或多个 Role 继承，这就是在 Role 中支持规则的继承。例如，一个用户 Role，如 “sally”，可以属于一个或多个 Role，如：“editor”和“administrator”。开发者可以分别给“editor”和“administrator”分配规则，而“sally”将从它们俩继承规则，不需要直接给“sally”分配规则。

| 注意
因为 Zend_Acl 支持从多个 Role 继承规则，它们彼此间可能会有冲突，有必要很清楚地解决这些冲突。Zend_Acl 通过把最近继承的 Role 作为最高优先级来解决潜在的冲突。换句话说，从最近继承的 Role 开始，一旦发现一个 “parent” Role 的规则，其它的规则将不被考虑，因为最高优先级的规则已经找到。

### 2.1.3. 创建访问控制列表(ACL)

ACL 可以表示任何一组物理或虚拟对象，然而，作为示范，我们将创建一个基本的内容管理系统的 ACL，在一个范围很宽的多样化区域里，它将维护若干个等级的组。为创建一个新的 ACL 对象，我们不带参数地实例化这个 ACL.

    <?php
    require_once 'Zend/Acl.php';

    $acl = new Zend_Acl();

| 注意
缺省地，Zend_Acl是一个“白名单”实现，这就意味着除非开发者指定，Zend_Acl 禁止任何 Role 对任何 Resource 的任何访问权限。

### 2.1.4. 注册角色(Role)

内容管理系统总是几乎需要一个等级结构的许可来决定它的用户的授权能力。作为示范，“Guest”组允许有限的访问，“Staff”适合大多数的执行日常操作的CMS用户，“Editor”组适合于发布、复核、存档和删除内容，最后“Administrator”组的任务包括所有其它组的内容并包括敏感的信息、用户管理、后台配置数据和备份/导出。这组许可可以被表示为一个 Role 注册表，允许每个组从“”组继承权限，也可以为单一的组提供独特的权限。这些许可可以表示如下：

表 2.1. 一个CMS范例的访问控制

名称 | 独特的许可 | 从...继承的许可
--- | --- | ---
Guest | View | N/A
Staff | Edit, Submit, Revise | Guest
Editor | Publish, Archive, Delete | Staff
Administrator | (Granted all access) | N/A

对于这个范例，`Zend_Acl_Role` 被使用，但任何实现 `Zend_Acl_Role_Interface` 的对象是可接受的。这些组可以被添加到 Role 注册表如下：

    <?php
    require_once 'Zend/Acl.php';

    $acl = new Zend_Acl();

    // 用 Zend_Acl_Role 把组添加到 Role 注册表
    require_once 'Zend/Acl/Role.php';

    // Guest 不继承访问控制
    $roleGuest = new Zend_Acl_Role('guest');
    $acl->addRole($roleGuest);

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

    /* 另外, 上面的也可这样来写：
    $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 包含了相关的 Roles，可以建立规则来定义 Roles 如何访问 Resources。你也许注意到我们在这个范例里没有定义任何特定的 Resources， 这简单地表示这些规则适用于所有 Resources。Zend_Acl 提供一个实现，籍此，规则只需要被分配从一般到特殊，最小化规则的需求，因为 Resources 和 Roles 继承由它们祖先定义的规则。

因此，我们可以用最少量的代码来定义适度复杂的规则。应用上面定义的基本许可：

    <?php
    require_once 'Zend/Acl.php';

    $acl = new Zend_Acl();

    require_once 'Zend/Acl/Role.php';

    $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');

在上面 `allow()` 中调用中 `null` 的值用来表明 allow 规则适用于所有的 Resources。

### 2.1.6. 查询 ACL

我们现在有一个灵活的 ACL 可以用来决定请求者在整个 web 应用里是否拥有执行功能的许可。用`isAllowed()`方法来执行查询相当简单：

    <?php
    echo $acl->isAllowed('guest', null, 'view') ?
         "allowed" : "denied"; // 允许

    echo $acl->isAllowed('staff', null, 'publish') ?
         "allowed" : "denied"; // 禁止

    echo $acl->isAllowed('staff', null, 'revise') ?
         "allowed" : "denied"; // 允许

    echo $acl->isAllowed('editor', null, 'view') ?
         "allowed" : "denied"; // 允许，因为从 guest 继承而来

    echo $acl->isAllowed('editor', null, 'update') ?
         "allowed" : "denied"; // 禁止，因为对于 'update' 没有 allow 规则

    echo $acl->isAllowed('administrator', null, 'view') ?
         "allowed" : "denied"; // 允许，因为 administrator 有所有权限

    echo $acl->isAllowed('administrator') ?
         "allowed" : "denied"; // 允许，因为 administrator 有所有权限

    echo $acl->isAllowed('administrator', null, 'update') ?
         "allowed" : "denied"; // 允许，因为 administrator 有所有权限

上一页 |  | 下一页
1.9. Zend::initRegistry($registry = 'Zend_Registry') | 起始页 | 2.2. 精细的访问控制