| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- EN-Revision: 24249 -->
- <!-- Reviewed: no -->
- <sect1 id="learning.multiuser.authorization">
- <title>Fabriquer un système de gestion d'autorisations avec Zend Framework</title>
- <sect2 id="learning.multiuser.authorization.intro">
- <title>Introduction à l'autorisation</title>
- <para>
- Après qu'un utilisateur se soit authentifié, une application peut proposer différentes
- règles d'accès à ses différentes ressources (parties). Le procédé qui consiste à savoir
- "qui a le droit de faire quoi" est nommé "gestion des autorisations". Dans sa forme la
- plus simple l'autorisation est la composition de trois facteurs:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- l'identitié de la personne souhaitant des droits - le rôle (qui?)
- </para>
- </listitem>
- <listitem>
- <para>
- la ressource demandée (sur quoi?)
- </para>
- </listitem>
- <listitem>
- <para>
- et optionnellement le privilège - le droit (quoi?)
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Dans Zend Framework, le composant <classname>Zend_Acl</classname> vous propose de créer
- ces trois entités remarquables, de les associer et de les interroger dans le futur.
- </para>
- </sect2>
- <sect2 id="learning.multiuser.authorization.basic-usage">
- <title>Utilisation de base de Zend_Acl</title>
- <!-- explain the interaction with a User object, how -->
- <para>
- En utilisant <classname>Zend_Acl</classname>, n'importe quel modèle peut servir de rôle
- ou de ressource en implémentant l'interface adéquate. Pour créer des rôles, implémentez
- <classname>Zend_Acl_Role_Interface</classname>, qui définit la méthode
- <methodname>getRoleId()</methodname>. Pour créer des ressources, implémentez
- <classname>Zend_Acl_Resource_Interface</classname> qui définit la méthode
- <methodname>getResourceId()</methodname>.
- </para>
- <para>
- Nous allons faire une démonstration avec un modèle simple. On peut le relier avec notre
- système d'<acronym>ACL</acronym> en implémentant
- <classname>Zend_Acl_Role_Interface</classname>. La méthode
- <methodname>getRoleId()</methodname> retournera "guest" lorsque l'ID est inconnu,
- ou l'ID du rôle lorsque celui-ci aura été affecté. Cette valeur peut provenir de n'importe
- où, probablement qu'elle proviendra d'une définition faite en base de données.
- </para>
- <programlisting language="php"><![CDATA[
- class Default_Model_User implements Zend_Acl_Role_Interface
- {
- protected $_aclRoleId = null;
- public function getRoleId()
- {
- if ($this->_aclRoleId == null) {
- return 'guest';
- }
- return $this->_aclRoleId;
- }
- }
- ]]></programlisting>
- <para>
- Le concept des utilisateurs ayant des rôles est simple à comprendre, mais l'application
- peut consommer plusieurs modèles et en retrouver des "ressources" qui seront
- consommables par les rôles. Nous utiliserons simplement des billets de blog comme
- ressources dans nos exemples, et comme les ressources sont des objets, nous ferons
- en sorte que l'ID d'un billet blog soir 'blogPost', naturellement cette valeur peut
- être calculée dynamiquement en fonction du besoin.
- </para>
- <programlisting language="php"><![CDATA[
- class Default_Model_BlogPost implements Zend_Acl_Resource_Interface
- {
- public function getResourceId()
- {
- return 'blogPost';
- }
- }
- ]]></programlisting>
- <para>
- Maintenant que nous avons au minimum un rôle et une ressource, définissons règles qui les
- lient. Ces règles seront lues lorsque le système recevra une requête d'acl demandant ce
- qu'il est possible de faire avec tel rôle, telle ressource et éventuellement tel privilège.
- </para>
- <para>
- Imaginons les règles suivantes:
- </para>
- <programlisting language="php"><![CDATA[
- $acl = new Zend_Acl();
- // mise en place des rôles
- $acl->addRole('guest');
- // owner hérite du rôle guest
- $acl->addRole('owner', 'guest');
- // ajout de ressources
- $acl->addResource('blogPost');
- // ajout de privilèges liant des rôles et des ressources
- $acl->allow('guest', 'blogPost', 'view');
- $acl->allow('owner', 'blogPost', 'post');
- $acl->allow('owner', 'blogPost', 'publish');
- ]]></programlisting>
- <para>
- Les règles ci-dessus sont très simples: deux rôles "guest"(invité) et "owner"
- (propriétaire), et une ressource "blogPost"(billet). Les invités sont autorisés
- à voir les billets, les propriétaires peuvent poster et publier des billets. Pour
- requêter le système, procédez alors comme suit:
- </para>
- <programlisting language="php"><![CDATA[
- // Imaginons que le modèle User soit de type "guest"
- $guestUser = new Default_Model_User();
- $ownerUser = new Default_Model_Owner('OwnersUsername');
- $post = new Default_Model_BlogPost();
- $acl->isAllowed($guestUser, $post, 'view'); // true
- $acl->isAllowed($ownerUser, $post, 'view'); // true
- $acl->isAllowed($guestUser, $post, 'post'); // false
- $acl->isAllowed($ownerUser, $post, 'post'); // true
- ]]></programlisting>
- <para>
- Comme vous pouvez le voir le système répond comme il faut dans la mesure où les
- invités peuvent lire les billets mais seuls les propriétaires peuvent en ajouter.
- Cependant ce système peut sembler manquer de dynamisme. Comment vérifier qu'un
- utilisateur spécifique est bien propriétaire d'un billet spécifique avant de
- l'autoriser à le publier ? Autrement dit, on veut s'assurer que seuls les
- propriétaires des billets peuvent publier ceux-ci, et pas ceux des autres.
- </para>
- <para>
- C'est là qu'entrent en jeu les assertions. Les assertions sont des vérifications
- supplémentaires à effectuer en même temps que la vérification de la règle d'acl.
- Ce sont des objets. Utilisons notre exemple avec une assertion:
- </para>
- <programlisting language="php"><![CDATA[
- class OwnerCanPublishBlogPostAssertion implements Zend_Acl_Assert_Interface
- {
- /**
- * Cette assertion va recevoir le User et le BlogPost actuels.
- *
- * @param Zend_Acl $acl
- * @param Zend_Acl_Role_Interface $user
- * @param Zend_Acl_Resource_Interface $blogPost
- * @param $privilege
- * @return bool
- */
- public function assert(Zend_Acl $acl,
- Zend_Acl_Role_Interface $user = null,
- Zend_Acl_Resource_Interface $blogPost = null,
- $privilege = null)
- {
- if (!$user instanceof Default_Model_User) {
- throw new Exception(__CLASS__
- . '::'
- . __METHOD__
- . ' s'attend à un rôle'
- . ' instance de User');
- }
- if (!$blogPost instanceof Default_Model_BlogPost) {
- throw new Exception(__CLASS__
- . '::'
- . __METHOD__
- . ' s'attend à un rôle'
- . ' instance de BlogPost');
- }
- // Si le rôle est publisher, il peut toujours modifier son billet
- if ($user->getRoleId() == 'publisher') {
- return true;
- }
- // vérifions que qui que ce soit, il modifie uniquement ses propres billets
- if ($user->id != null && $blogPost->ownerUserId == $user->id) {
- return true;
- } else {
- return false;
- }
- }
- }
- ]]></programlisting>
- <para>
- Pour faire intervenir l'assertion dans les <acronym>ACL</acronym>, nous les utilisons comme ceci:
- </para>
- <programlisting language="php"><![CDATA[
- // remplacez ceci:
- // $acl->allow('owner', 'blogPost', 'publish');
- // par cela:
- $acl->allow('owner',
- 'blogPost',
- 'publish',
- new OwnerCanPublishBlogPostAssertion());
- // ajoutons aussi le rôle "publisher" qui a accès à tout
- $acl->allow('publisher', 'blogPost', 'publish');
- ]]></programlisting>
- <para>
- Maintenant, dès que l'<acronym>ACL</acronym> est consultée pour savoir si un propriétaire
- peut publier un billet, cette assertion sera vérifiée. Elle s'assure que sauf si le rôle
- est 'publisher' le propriétaire a bien écrit le billet. Dans cet exemple, nous vérifions
- pour savoir si l'attribut <property>ownerUserId</property> du billet correspond à
- l'identifiant de l'utilisateur en question.
- </para>
- </sect2>
- </sect1>
|