Zend Tutorial – Zend Acl über ini-Datei

Es existieren 2 Module:

  • bibo (Bücherverwaltung)
  • login (Loginmodul)

Folgendes Rechtemanagement soll umgesetzt werden:
admin, user, guest

  • Admin bekommt vollen Zugriff auf auf Modul bibo und Modul login
  • User bekommt Zugriff
    • auf die Bibo-Actions: Index, Ausleihen, Zurückgeben, Suchen
    • vollen Zugriff auf Login
  • gast bekommt Zugriff
    • auf die Bibo-Action: Index
    • auf die Login-Actions:index, login (logout braucht der gast nicht, sonst wäre er ein user)

Das Rechtemanagement soll über ein .ini-Datei konfigurierbar sein.

Die eigentlichen Nutzer werden aus einer simplen sqlite Datenbank ausgelesen. Die Tabelle heißt simplerweise ‚users‘
und besitzt die Spalten ‚u_id‘, ‚u_username‘, ‚u_passwort‘, ‚u_role‘.
In meinem Fall hat die Tabelle zwei Einträge:

  • 1, admin, admin, admin (Loginname:admin, Passwort:admin, Rolle:admin)
  • 2, test, test, user (Loginname:test, Passwort:test, Rolle:user)

Analog zu den Zend ACL Tutorials (Kommentare beachten) werden als Plugin im Ordner application/Plugin/Auth die folgenden 3 Dateien angelegt:

  • AccessControl.php
  • Acl.php
  • AuthAdapter.php

Neu hinzu kommt nun die acl.ini im Ordner application/configs/acl.ini

Die Datei AuthAdapter.php bildet die Schnittstelle zu der SQLite-Datenbank:

class Plugin_Auth_AuthAdapter extends Zend_Auth_Adapter_DbTable
{
    public function __construct()
    {
        parent::__construct();
        $this->setTableName('users');
        $this->setIdentityColumn('u_username');
        $this->setCredentialColumn('u_passwort');
    }
}

Der Tabellenname wird wie oben bereits festgelegt auf ‚user‘ gesetzt. Die Spalte mit dem Loginnamen heißt ‚u_username‘, das dazu gehörige Passwort steht in der Spalte ‚u_passwort‘.

Die Datei AccessControl.php ist für das Login-Handling zuständig. Sie führt die Datenbankabfrage bzgl. der Nutzerdaten durch und prüft, ob das Login korrekt ist. Für den Fall, dass der Login nicht korrekt ist, oder der Nutzer keine Rechte besitzt wird die Weiterleitung auf eine Fehlerseite oder das Loginpanel vorgenommen.

class Plugin_Auth_AccessControl extends Zend_Controller_Plugin_Abstract
{
    protected $_auth;
    protected $_acl;
    
    public function __construct(Zend_Auth $auth, Zend_Acl $acl)
    {
        $this->_auth = $auth;
        $this->_acl = $acl;
    }
    
    public function routeStartup(Zend_Controller_Request_Abstract $request)
    {
        if (!$this->_auth->hasIdentity() 
            && null !== $request->getPost('login_user') 
            && null !== $request->getPost('login_password')) 
        {
            // POST-Daten bereinigen
            $filter = new Zend_Filter_StripTags();
            $username = $filter->filter($request->getPost('login_user'));
            $password = $filter->filter($request->getPost('login_password'));
             
            if(!empty($username))
            {
                //Datenbankabfrage
                $authAdapter = new Plugin_Auth_AuthAdapter();
                $authAdapter->setIdentity($username);
                $authAdapter->setCredential($password);
                $result = $this->_auth->authenticate($authAdapter);
                
                //Fehlermeldung setzen, wenn Login falsch
                if($result->getCode() != 1)
                {
                     
                      $view = Zend_Layout::getMvcInstance()->getView();
                      $view->assign(array('fehler'=>'Login inkorrekt! Bitte korrekten Login eingeben!'));
                }
                
                if($result->getCode() == 1)
                {
                     
                      $view = Zend_Layout::getMvcInstance()->getView();
                      $view->assign(array('weiterleitung'=>'true'));
                }
              
                if ($result->isValid()) 
                { 
                    $storage = $this->_auth->getStorage();
                    // die gesamte Tabellenzeile in der Session speichern,
                    // wobei das Passwort unterdrückt wird
                    $storage->write($authAdapter->getResultRowObject(null, 'password'));
                }
            } 
        }
        
    }
    
    public function preDispatch(Zend_Controller_Request_Abstract $request)
    {
        if ($this->_auth->hasIdentity() && is_object($this->_auth->getIdentity())) 
        {
            $role = $this->_auth->getIdentity()->u_role;
        }
        else
        {
            $role = 'guest';
        }
        
        $module = $request->getModuleName();
        
        // Ressourcen = Modul -> kann hier geändert werden!
        $resource = $module;
        if (!$this->_acl->has($resource)) 
        {
            $resource = null;
        }
        if (!$this->_acl->isAllowed($role, $resource, $request->getActionName()))
        {
            if ($this->_auth->hasIdentity()) 
            {
                // angemeldet, aber keine Rechte -> Fehler!
                $request->setModuleName('login');
                $request->setControllerName('error');
                $request->setActionName('noaccess');
            }
            else
            {
                // nicht angemeldet -> Login
                $request->setModuleName('login');
                $request->setControllerName('index');
                $request->setActionName('index');
            }
        }
    }
}

Bevor wir uns der Acl.php zuwenden, sollten wir nun im application/configs Ordner die Datei acl.ini gemäß unseren Rechtevorstellungen befüllen. Für unser Beispiel sollte das wie folgt aussehen:

;#####################################
;# Bsp.: Module.Role.x = Action #
;#####################################

bibo.guest.0 = index

bibo.user.0 = index
bibo.user.1 = ausleihen
bibo.user.2 = leihen
bibo.user.3 = suchen
bibo.user.4 = zurueck

bibo.admin.0 = all

login.guest.0 = index
login.guest.1 = login

login.user.0 = all

login.admin.0 = all

Wir setzen unsere Zugriffsrechte nach dem Schema Module.Role.FortlaufendeZahl
Möchtest Du alle Controller einer Resource für eine Rolle freischalten, so kannst Du das wie im Beispiel analog der Zeile

bibo.admin.0 = all

realisieren.

Die Datei Acl.php liest nun die Config-Datei acl.ini ein und setzt die entsprechend der Konfiguration festgelegten Rechte im
Anwendungskontext.

class Plugin_Auth_Acl extends Zend_Acl
{
    protected $_config;
    public function __construct($aclConfig = null)
    {
        //Pfad zur acl.ini setzen
        if($aclConfig)
        {    
             //Wenn $aclConfig gesetzt ist dann wird diese Datei als Config-Datei verwendet
             $this->_config = (string) APPLICATION_PATH."/configs/".$aclConfig;
        }
        else 
        {
            $this->_config = (string) APPLICATION_PATH."/configs/acl.ini";
        }
        
        //Prüft ob die Config-Datei vorhanden ist
        if(file_exists($this->_config))
        {
            //Config einlesen und in ein Array packen
            $config = new Zend_config_Ini($this->_config);
            $config = $config->toArray();
            
            foreach ($config as $res=>$value)
            {
                //Hinzufügen der verfügbaren Resourcen
                $this->addResource(new Zend_Acl_Resource($res)); 
                foreach ($value as $role=>$access)
                {
                    if(!$this->_getRoleRegistry()->has($role))
                    {
                        //Hinzufügen der verfügbaren Rollen
                        $this->addRole(new Zend_Acl_Role($role));
                    }
                    foreach ($access as $rules)
                    {
                        /* Setzen der Zugriffsrechte:
                           Falls access auf all gesetzt wird, erlaube alles für die Resource,
                           ansonsten definierte Rollen aus acl.ini */
                        if($rules == 'all')
                        {
                            $this->allow($role, $res, null);
                        }
                        else
                        {
                            $this->allow($role, $res, $rules);    
                        }
                    }
                }
            }
        }
        else
        {
            throw new Zend_Acl_Exception('Keine Config-Datei /../application/configs gefunden');
        }
    }
}

Damit ist die Grundfunktionalität des ZendAcl-Plugins um eine Konfigurationsdatei erweitert wurden. Man kann nun besser den Überblick zwischen PHP-Code und Konfiguration der Anwendung behalten.

Kommentar verfassen