Gestion des permissions, les privilèges avec Zend_Acl 3/3
Après avoir créé les tables de la base de données et les modèles, voici quelques explications sur le traitement des données pour en définir les permissions.
Enfin nous allons découvrir comment sont gérées les permissions sur CMS Zend. Je vous rassure, il n'y a rien d'exceptionnel, sauf le fait que seul les privilèges du rôle qui visite le site sont chargées (guest, member, su, ...).
Je vais décortiquer pour vous cette classe.
<?php class Acl extends Zend_Acl { private $_config = null; private $_MResources = null; private $_MRoles = null; ?>
Je commence par déclarer les attributs généraux à l'objet avec $_MResources qui va stocker le modèle "resources" et $_MRoles pour le modèle "roles". Quant a $_config, vous l'aurez certainement compris que c'est les configurations de base (sous forme de fichier ini dans notre cas).
<?php public function __construct($role) { $registry = Zend_Registry::getInstance(); $this->_config = $registry->get('config'); $this->_MResources = new Models_Resources; $this->_MRoles = new Models_Roles; if (is_null($role)) { $role = $this->_config->acl->defaultRole; } $this->setRoles($role); $this->setResources(); $this->setPrivileges($role); } ?>
Dans la méthode __construct(), je vais récupérer mon fichier de configuration. Si aucun rôle n'est défini dans la variable $role passé en paramètre de la méthode __construct(), je récupère le rôle par défaut de mon fichier de configuration. J'appelle le modèle traitant les ressources dont on aura besoin dans d'autres méthodes. Pour terminer, je fais référence à trois méthodes...
<?php private function setRoles($role) { $rowRole = $this->_MRoles->getRoleByName($role); if (!empty($rowRole)) { if ($rowRole->heritage === null) { $this->addRole(new Zend_Acl_Role($rowRole->name)); } if ($rowRole->heritage !== null) { $this->addHeritages($rowRole->heritage, $rowRole->name); } } } ?>
Je vais chercher les informations sur le rôle avec la méthode getRoleByName($role) et je vais en profiter pour mettre en place l'ensemble de ses héritages grâce à la fonction addHeritages() qui suit.
<?php private function addHeritages($heritages, $role) { $heritages = explode(',', $heritages); foreach($heritages as $heritage) { $roleHeritage = $this->_MRoles->getRoleById($heritage); if (!$this->hasRole($roleHeritage->name)) { $this->addRole(new Zend_Acl_Role($roleHeritage->name)); if ($roleHeritage->heritage !== null) { $this->addHeritages($roleHeritage->heritage, $role); } $this->addRole(new Zend_Acl_Role($role), $roleHeritage->name); } } return true; } ?>
La méthode getRoleById($heritage) me permet d'aller chercher les rôles par le biais de leurs ID et ainsi les faire hériter à notre rôle.
Je n'ai pas eu le temps de tester cette fonction en détail, il se peut qu'elle ne soit pas complètement opérationnelle et qu'elle soit à améliorer lors d'héritages multiples. Si vous voyez une erreur, je vous invite à m'en faire part
<?php private function setResources() { $listResources = $this->_MResources->getLists(); foreach($listResources as $listResource) { if ($listResource->modules == $this->_config->resources->frontController->defaultModule) { $this->add(new Zend_Acl_Resource($listResource->controllers)); } else { if ($listResource->controllers == 'index' && $listResource->actions == 'index') { $this->add(new Zend_Acl_Resource($listResource->modules . '_' . $listResource->controllers)); } elseif ($listResource->controllers != 'index' && $listResource->actions == 'index') { $this->add(new Zend_Acl_Resource($listResource->modules . '_' . $listResource->controllers)); } } } } ?>
Ici je récupère la liste des ressources avec la méthode getList() (elle n'est pas présenté dans l'article sur les modèles, mais elle récupère simplement la liste des ressources). Ensuite je teste si le module corresponde au module définit par défaut dans le fichier de configuration. C'est-à-dire "public". Et je déclare sa ressource.
Sinon c'est uu autre module que je déclare sous la forme "module_controller".
<?php private function setPrivileges($role) { $roleRow = $this->_MRoles->getRoleByName($role); $listResources = $this->_MResources->getLists(); if ($roleRow->id === 1) { $this->allow($roleRow->name); } foreach($listResources as $listResource) { if ($listResource->modules == $this->_config->resources->frontController->defaultModule && $listResource->actions == 'index') { $this->allow($role, $listResource->controllers); } else { if ($listResource->modules == $this->_config->resources->frontController->defaultModuleAdmin && $listResource->actions == 'index') { if ($role == $this->_config->acl->defaultRole) { if ($listResource->controllers == 'index' && $listResource->actions == 'index') { $this->deny($roleRow->name, $listResource->controllers); } elseif ($listResource->controllers != 'index' && $listResource->actions == 'index') { $this->deny($roleRow->name, $listResource->modules . '_' . $listResource->controllers); } } else { if ($listResource->controllers == 'index' && $listResource->actions == 'index') { $this->allow($roleRow->name, $listResource->controllers); } elseif ($listResource->controllers != 'index' && $listResource->actions == 'index') { $this->allow($roleRow->name, $listResource->modules . '_' . $listResource->controllers); } } } } } $MPrivileges = new Models_Privileges; $privileges = $MPrivileges->getPrivilegesById($roleRow->id); foreach($privileges as $privilege) { $roleRow = $this->_MRoles->getRoleById($privilege->roles_id); $resource = $this->_MResources->getRowResourcesById($privilege->resources_id); $access = $privilege->access; if ($resource->modules == $this->_config->resources->frontController->defaultModule) { $this->$access($roleRow->name, $resource->controllers, $resource->actions); } else { $this->$access($roleRow->name, $resource->modules . '_' . $resource->controllers, $resource->actions); } } } } ?>
Enfin, je déclare les privilèges et comme je l'ai dit plus haut, je prends uniquement ceux du rôle qui visite le site. La méthode getRoleByName($role) me permet de récupérer les informations du rôle en question. Ensuite je teste si le rôle à pour id le chiffre un. Ce qui veut dire que c'est un super administrateur (dans la base de données l'id un correspond au su). Il à donc tous les privilèges.
La première boucle me permet de définir des privilèges par défaut :
- Si le module est celui par défaut (le module public) dans ce cas toutes les permissions sont accordées.
- Sinon, c'est un autre module.
Actuellement je ne gère que le module administrateur et il a deux cas possible :
- Le rôle est celui par défaut (guest) donc dans ce cas on refuse tous les accès.
- C'est un autre rôle on accord tout.
Pour finir, il reste une boucle qui affine les privilèges suivants les informations récupérées de la table privilèges. J'en profite en même temps pour récupérer l'accès de la ressource (deny/allow). Et là, encore une fois je teste si c'est le module par défaut qui est concerné ou non.
Du coup, la table privilège permet de définir les accès pour chaque action de chaque contrôler.
Il ne restera plus qu'à intégrer cette classe avec un plugin d'authentification afin de le mettre en œuvre le système Acl de Zend. Je vous invite à contribuer à cet article afin de faire évoluer ou corriger certains bugs de ce code.
J'ai essayé d'être le plus claire possible

Commentaires
Aucun commentaire pour le moment.
Ajouter un commentaire
Les commentaires pour ce billet sont fermés.