Programmer's Reference Guide
| アクセス制御の洗練 |
高度な使用法
ACL データの保存による永続性の確保
Zend_Acl は、特定のバックエンド技術 (たとえばデータベースやキャッシュサーバを使用した ACL データの保存など) に依存しないように作られています。 すべて PHP のみで実装されているので、Zend_Acl 用の管理ツールを独自に作成して 管理の手間を省くことも可能になっています。 ACL の管理を対話的に行いたいという場面も数多く発生するでしょう。そのため Zend_Acl では、アプリケーションのアクセス制御を設定したり、 それに対して問い合わせたりするためのメソッドを用意しています。
データの使用法にはさまざまなものが考えられるので、 ACL データの保存は、場面に応じて開発者側で考えることになります。 Zend_Acl はシリアライズ可能なので、ACL オブジェクトを PHP の » serialize() 関数でシリアライズできます。シリアライズした結果を、 ファイルやデータベースあるいはキャッシュなどのお好みの場所に保存できます。
アサーションを使用した条件付き ACL 規則の作成
あるリソースに対する特定のロールのアクセス権限が、 固定ではなく条件に応じて変化することもあります。 たとえば、アクセスを認めるのは午前 8 時から午後 5 時の間に限定するといった場合です。 別の例としては、ブラックリストに載っている特定の IP アドレスからのアクセスのみを拒否するといったことがあります。 Zend_Acl は、必要に応じた任意の条件にもとづく規則を組み込みでサポートしています。
Zend_Acl は、条件付きの規則を Zend_Acl_Assert_Interface でサポートしています。規則のアサーション用インターフェイスを使用するには、 これを実装したクラスで assert() メソッドを作成します。
- class CleanIPAssertion implements Zend_Acl_Assert_Interface
- {
- 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());
上のコードが作成する条件付き規則は、 誰からのアクセスであってもすべての権限を許可しますが、リクエスト元の IP アドレスが "ブラックリストに載っている" 場合にのみアクセスを拒否するというものです。 リクエスト元の IP が "クリーン" ではないとみなされた場合は、 アクセス許可規則が適用されません。この規則はすべてのロールおよびリソースの すべての権限に対して適用されるので、"クリーンではない" IP からのアクセスは拒否することになります。 しかし、これは特殊なケースです。通常は (つまり特定のロールやリソース、 権限を規則の対象とする場合)、アサーションに失敗して規則が適用されなかった場合には、 別の規則を使用してアクセスの可否を判断させるべきです。
アサーションオブジェクトの assert() メソッドは、認証問い合わせ (すなわち isAllowed()) が適用される ACL、ロール、リソース および権限に渡されます。これを用いて、必要な場所でアサーションクラスが 条件を判断します。
| アクセス制御の洗練 |
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.