Zend Framework FAQ: Wie setze ich eine ACL für eine Modul basierte Applikation um?

Montag, 26.10.2009

Bei der ersten Abstimmung für die Zend Framework Fragestunde, wurde diese Frage mit 37% der Stimmen auf Platz 1 gewählt: Wie setze ich eine ACL für eine Modul basierte Applikation um?

Hierfür müssen wir als erstes die Grundlage schaffen und festlegen, was eigentlich mit einer Modul basierten Applikation gemeint ist. Das Zend Framework bietet schon seit einen frühen Anfängen die Möglichkeit, eine Applikation in Module aufzuteilen. In einem Modul können somit Action-Controller, View-Skripte, Models, Formulare und mehr gekapselt werden. Die Klassen dieser Module bekommen einen eigenen vorangestellten Namensraum, damit es nicht zu Namenskonflikten kommen kann. Eine Zend Framework Applikation könnte somit aus den Modulen Gästebuch, Forum und CMS (für Ausgabe von Textbeiträgen) bestehen. Zusätzlich zu diesen Modulen gibt es in der Regel immer ein Default-Modul, dass sich unter anderem um die Auslieferung der Homepage kümmert. Zusammenfassend werden wir also mit den folgenden Module arbeiten:

  • default
  • guestbook
  • forum
  • cms

Um mit Zend_Acl eine ACL (Access Control List) umsetzen zu können, benötigen wir noch die Benutzerrollen. Wir verwenden an dieser Stelle die drei Benutzerrollen admin, editor und guest und gehen davon aus, dass in allen Modulen die selben Benutzerrollen verwendet werden sollen. Den Aspekt der Wiederverwendbarkeit der Module lasse ich an dieser Stelle bewusst unberücksichtigt. Denn dies würde das Ganze nur noch komplizierter machen.

Als nächstes müssen wir noch überlegen, wie wir die Ressourcen, Privilegien und Rechte in unserer ACL definieren. Hierbei gibt es verschiedene Ansätze. Wir könnten als Ressourcen unsere Models betrachten und deren Methoden als Privilegien einsetzen. Ein anderer Ansatz basiert auf dem Dreigespann Modul, Controller und Action. Diesen Ansatz möchte ich hier vorstellen. Als Privilegien verwenden wir die Namen der Aktionsmethoden und als Ressourcen die Namen der Action-Controller Klassen. Und wo bleibt das Modul? Ganz einfach, für jedes Modul erstellen wir eine eigene ACL. Dies hat auch den Vorteil, dass die ACL insgesamt nicht zu groß wird. Zudem können wir durch geschicktes Cachen der Zend_Acl Objekte zusätzlich die Performance steigern.

Hier folgt als Beispiel die ACL für unser CMS Modul. Die ACLs für die anderen Module sehen ähnlich aus und tragen die Klassennamen Default_Acl, Guestbook_Acl und Forum_Acl.

PHP:
  1. class Cms_Acl extends Zend_Acl
  2. {
  3.     public function __construct()
  4.     {
  5.         // Rollen anlegen
  6.         $this->addRole(new Zend_Acl_Role('guest'));
  7.         $this->addRole(new Zend_Acl_Role('editor'), 'guest');
  8.         $this->addRole(new Zend_Acl_Role('admin'), 'editor');
  9.        
  10.         // Ressourcen anlegen, jede Ressource entspricht einem Action-Controller
  11.         $this->addResource(new Zend_Acl_Resource('index'));
  12.         $this->addResource(new Zend_Acl_Resource('article'));
  13.         $this->addResource(new Zend_Acl_Resource('tag'));
  14.         $this->addResource(new Zend_Acl_Resource('comment'));
  15.        
  16.         // Privilegien und Rechte für Gäste anlegen
  17.         $this->allow('guest', 'index');
  18.         $this->allow('guest', 'article', array('index', 'show'));
  19.         $this->allow('guest', 'tag', array('index', 'show'));
  20.         $this->allow('guest', 'comment', array('index', 'show', 'create'));
  21.  
  22.         // Privilegien und Rechte für Redakteure anlegen
  23.         $this->allow('editor', 'article', array('create', 'update', 'delete'));
  24.         $this->allow('editor', 'tag', array('create', 'update'));
  25.         $this->allow('editor', 'comment', array('update', 'delete'));
  26.        
  27.         // Privilegien und Rechte für Admins anlegen
  28.         $this->allow('admin', 'article', array('approve', 'block'));
  29.         $this->allow('admin', 'tag', array('delete'));
  30.         $this->allow('admin', 'comment', array('mark-as-spam', 'hide'));
  31.     }
  32. }

Das ist keine große Sache und sollte jedem klar sein, der sich mit der Zend_Acl Komponente schon ein wenig befasst hat. Jetzt bleibt die Frage, wann wird die entsprechende ACL denn geladen. Dies kann erst passieren, nachdem das Routing statt gefunden hat und klar ist, welches Modul gerade aufgerufen wird. Dafür verwenden wir ein Plugin.

Das Plugin kümmert sich nur um die Benutzerrechte und nicht um die Authentifizierung. Es geht davon aus, dass diese bereits erfolgt ist. Das Plugin in an sich ist relativ selbsterklärend, hervorheben möchte ich nur, dass auf Basis des aktuellen Moduls der Klassenname der entsprechenden ACL erstellt wird. Der Rest sollte Routine sein. Wenn eine Benutzer nicht über entsprechende Rechte verfügt, wird er als Gast gebeten sich einzuloggen und als angemeldeter User bekommt einen entsprechenden Hinweis.

PHP:
  1. class Default_Controller_Plugin_Acl extends Zend_Controller_Plugin_Abstract
  2. {
  3.     public function routeShutdown(Zend_Controller_Request_Abstract $request)
  4.     {
  5.         // hole Module, Controller und Action
  6.         $module     = $request->getModuleName();
  7.         $controller = $request->getControllerName();
  8.         $action     = $request->getActionName();
  9.        
  10.         // hole Auth
  11.         $auth = Zend_Auth::getInstance();
  12.        
  13.         // hole Rolle
  14.         $role = $auth->hasIdentity()
  15.               ? Zend_Auth::getInstance()->getIdentity()->role
  16.               : 'guest';
  17.        
  18.         // erstelle Klassenname für ACL
  19.         $aclClass = ucfirst($module) . '_Acl';
  20.        
  21.         // Erstelle ACL Objekt
  22.         $acl = new $aclClass(); /* @var $acl Zend_Acl */
  23.        
  24.         // Prüfe Rechte
  25.         if (!$acl->isAllowed($role, $controller, $action))
  26.         {
  27.             // lege neue Action fest
  28.             $newAction = ('guest' == $role) ? 'login' : 'forbidden';
  29.            
  30.             // Ändere Request Objekt für neue Action
  31.             $request->setModuleName('default')
  32.                     ->setControllerName('user')
  33.                     ->setActionName($newAction);
  34.         }
  35.     }
  36. }

Das war es schon im Wesentlichen. Das Ganze ließe sich nun noch verfeinern, indem man sich z.B. eine Factory Methode schreibt, welche das Ermitteln des Klassennamens übernimmt. Dadurch kann die ACL auch außerhalb des Plugins anhand eines Moduls ermittelt werden. Diese Methode könnte My_Acl::factory() heißen, als Parameter $module entgegen nehmen und ein von Zend_Acl abgeleitetes Objekt zurückgeben. Diese Factory-Methode könnte sich dabei auch gleich um das Caching kümmern, so dass die ACLs nicht bei jedem Aufruf neu erstellt werden müssen.

Ich hoffe, die Ausgangsfrage ist somit im Wesentlichen beantwortet. Falls nicht, bitte in den Kommentaren melden. Natürlich auch bei Fragen zu diesem Beitrag.

Tweet this via redir.ec

Models im Zend Framework, zum Dritten in 3 Jahren

Donnerstag, 24.09.2009

Traditionen müssen gewahrt werden. Anscheinend ist der September immer der Monat, in dem ich mich intensiver mit dem Thema Models im Zend Framework beschäftige. Bereits vor 3 Jahren und im letzten Jahr habe ich darüber geschrieben, dass das Zend Framework im eigentlichen Sinne noch keine Implementation des Ms vom Model-View-Controller bereit stellt. Das Proposal, das im letzten Jahr noch vielversprechend aussah, ist mittlerweile wieder eingeschlafen. Und auch das Kapitel über Zend_Model wurde bisher immer noch nicht geschrieben. Doch wie ist denn nun der Stand der Dinge?

Über das Thema ist einiges in den Blogs zu lesen. Federico Cargnelutti hat im März eine kleine Serie zum Thema Domain-Driven-Design veröffentlicht und vor einigen Tagen noch das Thema DALs, DAOs und DataMapper aufgegriffen. Wer sich darunter nichts vorstellen kann, lese hier weiter:

Padraic Brady schreibt derzeit an seinem Open Book zum Zend Framework und hat auch schon zwei Kapitel zum Thema Models veröffentlicht. Diese sind unbedingt lesenswert:

Auch bei Matthew Weier O'Phinney ist eine kleine Artikelserie erschienen, die aber schon einige Monate auf dem Buckel hat. Er schreibt über den Einsatz von Zend_Form und Zend_Acl in einem Model sowie über eine Model Infrastruktur:

Und was ist nun offiziell im Zend Framework im Gange? Nicht wenige würden sich sehr darüber freuen, wenn das Zend Framework mehr Unterstützung zum Thema Models bereit stellen würde. Es gibt dabei zwar viele Ansätze und keinen goldenen Weg, aber dennoch würden Tipps und Anregungen die Arbeit erleichtern. Und dann noch ein paar nützliche und durchdachte Komponenten dazu, dann wäre alles gut. Und was soll ich sagen? Es kommt langsam Bewegung in die Sache, denn derzeit werden von Benjamin Eberlei zwei neue Komponenten vorbereitet: Zend_Entity und Zend_Db_Mapper. Der Proposal klingt sehr spannend und in ähnlicher Form wird dieser Ansatz auch schon im QuickStart des Zend Frameworks eingesetzt. Auch dort gibt es Mapper und Model Klassen sowie Instanzen von Zend_Db_Table.

Es bleibt also spannend.

http://www.ralfeggert.de/2006/09/07/fehlende-komponenten-im-zend-framework/

Tweet this via redir.ec


Better Tag Cloud