Programmer's Reference Guide
| 精细的访问控制 |
高级用法
保存 ACL 数据确保持久性
Zend_Acl 就是这样设计的,它不需要为 ACL 数据的存储而要求任何特别的后台技术如数据库或者缓冲服务器。它的完全的 PHP 实现使得在Zend_Acl之上构建定制的管理工具相当地容易和灵活。许多情形需要一些 ACL 的交互式维护,并且 Zend_Acl 为设定、查询、应用软件的访问控制提供了方法。
因为期望应用案例有多种变化来适应不同的情形,ACL 数据的存储因此留给开发者来完成。因为 Zend_Acl 是可序列化的,所以 ACL 的对象可以用 PHP 中的 » serialize() 函数来序列化,并且结果可以存在开发者所期望的任何地方,例如文件、数据库、或缓存机构。
使用声明(Assert)来编写条件性的 ACL 规则
有时候允许或禁止一个 Role 访问一个 Resource 的规则不是绝对的而是依靠不同的标准。例如,只有在 8:00am 和 5:00pm 之间,特定的访问才被允许。另外一个禁止访问的例子是因为一个请求来自于被标记为不良的 IP 地址。Zend_Acl 对基于无论开发者有什么需要的条件的规则实现有个内置的支持。
Zend_Acl 用 Zend_Acl_Assert_Interface 提供支持有条件的规则。为了使用规则声明接口,开发者写了一个实现接口中 assert() 方法的类。
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)
{
// ...
}
}}
一旦声明类可用,当分配有条件的规则时,开发者必需提供声明类的一个实例。用声明建立的规则只适用于当声明方法返回 true。
$acl = new Zend_Acl();
$acl->allow(null, null, null, new CleanIPAssertion());
上面的代码创建了一个有条件的 allow 规则,它允许所有人对所有资源有所有的访问权限,除非请求的 IP 列在“黑名单”上。如果一个请求来自于一个不是“清白”的 IP, 这个 allow 规则就不适用。因此这个规则适用于所有的 Roles、所有的 Resources 和所有的权限,一个“不清白”的 IP 将导致一个禁止访问。这是一个特例,对于其它所有案例(例如,一个特定的 Role、Resource、或者被指定规则的权限),一个失败的声明将导致规则不适用,并且其它规则将被用于决定访问是被允许或禁止。
为了给声明类提供一个上下文环境(Context)来决定所需的条件,Assert对象的 assert() 方法将以ACL、 Role、 Resource 和适用于授权查询(例如isAllowed())的权限作为参数。
| 精细的访问控制 |
Add A Comment
Please do not report issues via comments; use the ZF Issue Tracker.
If you have a JIRA/Crowd account, we suggest you login first before commenting.

Comments
require_once('Zend/Acl.php');
/* acl related tables
CREATE TABLE `acl_roles` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(45) DEFAULT NULL,
`parent_id` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `acl_resources` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(45) DEFAULT NULL,
`parent_id` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `acl_roles_resources` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`acl_role_id` int(10) unsigned NOT NULL,
`acl_resource_id` int(10) unsigned NOT NULL,
`privilege` varchar(45) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_role_res_priv` (`acl_role_id`,`acl_resource_id`,`privilege`)
);
*/
class MyAcl
{
private $acl = null;
function __construct()
{
$this->acl = new Zend_Acl();
$this->_initRoles();
$this->_initResources();
$this->_initPrivileges();
}
function isAllowed($some_role, $some_resource, $some_privilege)
{
return $this->acl->isAllowed($some_user, $some_resource, $some_action);
}
private function _initRoles()
{
$roles = AclRole::all();
foreach($roles as $role)
{
if($role->parent)
{
$parent = $this->acl->getRole($role->parent->name);
if(is_null($parent))
{
// if parent hasn't been created in memory, do so
$parent = new Zend_Acl_Role($role->parent->name);
$this->acl->addRole($parent);
}
$this->acl->addRole(new Zend_Acl_Role($role->name), $parent);
}
else
{
// only needs to be done if it doesn't exist
if(!$this->acl->hasRole($role->name))
{
$this->acl->addRole(new Zend_Acl_Role($role->name));
}
}
}
}
private function _initResources()
{
$resources = AclResource::all();
foreach($resources as $resource)
{
if($resource->parent)
{
$parent = $this->acl->get($resource->parent->name);
if(is_null($parent))
{
$parent = new Zend_Acl_Resource($resource->parent->name);
$this->acl->addResource($parent);
}
$this->acl->addResource(new Zend_Acl_Resource($resource->name), $parent);
}
else
{
if(!$this->acl->has($resource->name))
{
$this->acl->addResource(new Zend_Acl_Resource($resource->name));
}
}
}
}
private function _initPrivileges()
{
$privileges = AclRolesResource::all();
foreach($privileges as $privilege)
{
// make sure role and resource are valid
if($privilege->acl_role && $privilege->acl_resource)
{
$this->acl->allow($privilege->acl_role->name, $privilege->acl_resource->name, $privilege->privilege);
}
else
{
echo 'WARNING: unable to create privilege
// close the echo and add 4 parens
}
}
}
}
}
// you should be able to paste into any good editor and have it format.
Granted, if you're searching for "Zend_Acl" you probably know what an ACL is, and have some clue as to how to implement one with a DB back-end, but the complete and total lack of examples in the documentation is really, really disappointing.
I feel like if i were in Java World.
Excuse me but Java is not what i need for webApps. In need a framework to develop quickly, not one where i have to do a lot of POC to be sure it run as i want.
The "how's" of it took some time to learn, however it's taken some time, and some trial and error to learn how to do it.
There is enough documentation on Zend Framework here, and out there on the web, to learn how to do it. I hate to say to "ask google" but what you're asking for isn't a single function call. Rather, it's "programming" and it's something you have to put some effort into.
- a 15 year programming veteran
Agree with the comments re: poor docs.
As an analogy, if you buy a camera, the manual won't teach you how to be a great photographer. However, the manual will give photographers all of the information they need to be up and running quickly with that camera.
Hopefully, when I understand enough about how the framework is put together, I'll be able to give some of my time to help out in some way.