Programmer's Reference Guide

Verfeinern der Zugriffskontrolle

Fortgeschrittene Verwendung

Dauerhafte Speicherung von ACL-Daten

Zend_Acl wurde so entwickelt, dass keine spezielle Backend Technologie benötigt wird, wie z.B. eine Datenbank oder ein Cache Server, um die ACL-Daten zu speichern. Ihre vollständige PHP-Implementation ermöglicht angepasste Administrationstools, die relativ einfach und flexibel auf Zend_Acl aufbauen. Viele Situationen erfordern eine interaktive Wartung der ACL und Zend_Acl stellt Methoden für das Einrichten und Abfragen der Zugriffskontrolle einer Anwendung.

Die Speicherung der ACL-Daten ist deshalb die Aufgabe des Entwicklers, da sich die Anwendungsfälle für verschiedene Situationen erwartungsgemäß stark unterscheiden. Da Zend_Acl serialisierbar ist, können ACL-Objekte mit der PHP-Funktion » serialize() serialisiert werden und das Ergebnis kann überall gespeichert werden, wo es der Entwickler möchte, wie z.B. in einer Datei, in einer Datenbank oder mit einem Cache-Mechanismus.

Schreiben von bedingten ACL-Regeln mit Zusicherungen

Manchmal soll eine Regel für das Erlauben oder Verbieten des Zugriffs auf eine Ressource nicht absolut sein, sondern von verschiedenen Kriterien abhängen. Nehmen wir zum Beispiel an, dass ein bestimmter Zugriff erlaubt sei, aber nur zwischen 08:00 und 17:00 Uhr. Ein anderes Beispiel könnte sein, dass der Zugriff verboten wird, weil eine Anfrage von einer bestimmten IP-Adresse kommt, die als Missbrauchsquelle markiert worden ist. Zend_Acl bietet eine eingebaute Unterstützung für die Implementierung von Regeln, die auf Bedingungen basieren, die der Entwickler benötigt.

Zend_Acl bietet Unterstützung für bedingte Regeln mit dem Zend_Acl_Assert_Interface. Um das Regelzusicherungsinterface benutzen zu können, schreibt der Entwickler eine Klasse, welche die Methode assert() des Interfaces implementiert:

  1. class CleanIPAssertion implements Zend_Acl_Assert_Interface
  2. {
  3.     public function assert(Zend_Acl $acl,
  4.                            Zend_Acl_Role_Interface $role = null,
  5.                            Zend_Acl_Resource_Interface $resource = null,
  6.                            $privilege = null)
  7.     {
  8.         return $this->_isCleanIP($_SERVER['REMOTE_ADDR']);
  9.     }
  10.  
  11.     protected function _isCleanIP($ip)
  12.     {
  13.         // ...
  14.     }
  15. }

Sobald eine Zusicherungsklasse verfügbar ist, muss der Entwickler eine Instanz dieser Zusicherungsklasse bei der Zuordnung bedingter Regeln übergeben. Eine Regel, die mit einer Zusicherung angelegt wird, wird nur angewendet, wenn die Zusicherungsmethode TRUE zurück gibt.

  1. $acl = new Zend_Acl();
  2. $acl->allow(null, null, null, new CleanIPAssertion());

Der obige Code legt eine bedingte Erlaubnisregel an, die den Zugriff für alle Rechte auf alles und von jedem erlaubt, außer wenn die anfordernde IP auf einer "Blacklist" ist. Wenn die Anfrage von einer IP kommt, die nicht als "sauber" betrachtet wird, wird die Erlaubnisregel nicht angewandt. Da die Regel auf alle Rollen, alle Ressourcen und alle Rechte zutrifft, würde eine "unsaubere" IP zu einem Zugriffsverbot führen. Dies ist ein besonderer Fall und es sollte verstanden werden, dass in allen anderen Fällen (d.h. wenn eine spezielle Rolle, Ressource oder Recht für die Regel spezifiziert wird) eine fehlerhafte Zusicherung dazu führt, dass die Regel nicht angewandt wird und andere Regeln verwendet werden um zu ermitteln, ob der Zugriff erlaubt oder verboten ist.

Der Methode assert() eines Zusicherungsobjektes werden die ACL, Rolle, Ressource und die Rechte übergeben, auf welche die Autorisierungsabfrage (d.h., isAllowed()) passt, um den Kontext für die Zusicherungsklasse bereit zu stellen, um die Bedingungen zu ermitteln wo erforderlich.


Verfeinern der Zugriffskontrolle

Comments

Yeah, Zend should try to create example to go with the documentation
So there is no example on how to create auth/acl with roles and permissions stored in a mysql database, which is what probably 90% of php applications do; neither here nor in the Learning Zend Framework section; rather disappointing
lienlook is correct. absolutely disappointing.
There is plenty of material here to allow you to create rules, roles and privileges. Bundling it all up into a cache/database/session is outside the scope of these pages, but trivial if you read those sections too
Yep, very disappointing. Then again, all of Zend documentation sucks to the point of borderline worthlessness. Too bad, because it's a great tool.
I can't believe how lazy some of you are. Here is a class that uses php.activerecord (and mysql) to get roles, resources, and the privileges...

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
//oops I guess there is a limit to a comment
// close the echo and add 4 parens

}
}
}
}
}

// you should be able to paste into any good editor and have it format.
It's lazy to expect examples / code samples to be provided for any particular task that the Zend Framework can be used for, as if that was some kind of natural entitlement, however it's also lazy to simply explain ZF functionality in a very abstract, no-realistic-examples kind of fashion.

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.
If the correct answer to asking for a working example for a common use case is "I can't believe how lazy some of you are" and 100+ lines of code, then perhaps this isn't the framework for me.
This documentation really needs more working examples. The outlines alone aren't enough to get it working. One reason I love php.net is because every function they have has documented examples which clearly put you on the right path.
I agree most of people here, Symfony2 has concrete sample, why ZF don't ?
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.
Hmm... even though I agree with the fact there is a lack of examples, the doc itself are pretty clear and simple to understand. The ZF doc is here to explain how it works and its scope. Starting from this, it should be good enough to write some tests on your own application to see how it handles. Nothing more. It shouldn't take that much amount of time. As a developer, you're supposed to find your way first on your own, then thanks to the logs and docs, and at last, with the help of people (forums, workmates, technical lead...).
Fact is, I have implemented access control using PHP + MySQL + Zend Framework.

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
Here's another thing to throw into the mix - how do you persist assertions?

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.

+ 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.

  • BBCode is allowed in the comment markup

  • Select a Version

    Languages Available

    Components

    Search the Manual