multiuser-authorization.xml 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- EN-Revision: 19809 -->
  3. <!-- Reviewed: no -->
  4. <sect1 id="learning.multiuser.authorization">
  5. <title>Erstellung eines Authorisations Systems in Zend Framework</title>
  6. <sect2 id="learning.multiuser.authorization.intro">
  7. <title>Einführung in Authorisation</title>
  8. <para>
  9. Nachdem ein Benutzer als authentisch identifiziert wurde, kann eine Anwendung mit Ihrem
  10. Geschäft weitermachen und einige nützliche und gewünschte Ressourcen an den Konsumenten
  11. liefern. In vielen Fällen können Anwendungen andere Ressource Typen enthalten, wobei
  12. einige Ressourcen auch striktere Regeln betreffend Zugriff haben können. Dieser Prozess
  13. der Erkennung, wer Zugriff zu welchen Ressourcen hat, ist der Prozess der
  14. "Authorisierung". Authorisierung in seiner einfachsten Form ist die Komposition der
  15. folgenden Elemente:
  16. </para>
  17. <itemizedlist>
  18. <listitem>
  19. <para>
  20. die Identität von dem der Zugriff wünscht
  21. </para>
  22. </listitem>
  23. <listitem>
  24. <para>
  25. die Ressource für welche die Identität den Zugriff anfragt um Sie zu konsumieren
  26. </para>
  27. </listitem>
  28. <listitem>
  29. <para>
  30. und optional, was der Identität erlaubt ist mit der Ressource zu tun
  31. </para>
  32. </listitem>
  33. </itemizedlist>
  34. <para>
  35. Im Zend Framework behandelt die Komponente <classname>Zend_Acl</classname> die Arbeit
  36. der Erstellung eines Baums von Rollen, Ressourcen und Privilegien um
  37. Authorisationsanfragen zu managen und abzufragen.
  38. </para>
  39. </sect2>
  40. <sect2 id="learning.multiuser.authorization.basic-usage">
  41. <title>Grundsätzliche Verwendung von Zend_Acl</title>
  42. <!-- explain the interaction with a User object, how -->
  43. <para>
  44. Wenn <classname>Zend_Acl</classname> verwendet wird können beliebige Modelle als Rollen
  45. oder Ressourcen fungieren indem einfach das richtige Interface implementiert wird. Um
  46. als Rolle verwendet zu werden muss die Klasse <classname>Zend_Acl</classname>
  47. implementieren, welche nur <methodname>getRoleId()</methodname> benötigt. Um als
  48. Ressource zu verwenden muss eine Klasse
  49. <classname>Zend_Acl_Resource_Interface</classname> implementieren wofür die Klasse so
  50. ähnlich die <methodname>getResourceId()</methodname> Methode implementieren muss.
  51. </para>
  52. <para>
  53. Anbei wird ein einfaches Benutzermodell demonstriert. Dieses Modell kann einen Teil in
  54. unserem <acronym>ACL</acronym> System übernehmen indem einfach
  55. <classname>Zend_Acl_Role_Interface</classname> implementiert wird. Die Methode
  56. <methodname>getRoleId()</methodname> gibt die Id "guest" zurück wenn die Id nicht
  57. bekannt ist, oder die Id der Rolle welche mit dem aktuellen Benutzerobjekt verknüpft
  58. ist. Dieser Wert kann effektiv von überall kommen, eine statische Definition oder
  59. vielleicht dynamisch von der Datenbankrolle des Benutzers selbst.
  60. </para>
  61. <programlisting language="php"><![CDATA[
  62. class Default_Model_User implements Zend_Acl_Role_Interface
  63. {
  64. protected $_aclRoleId = null;
  65. public function getRoleId()
  66. {
  67. if ($this->_aclRoleId == null) {
  68. return 'guest';
  69. }
  70. return $this->_aclRoleId;
  71. }
  72. }
  73. ]]></programlisting>
  74. <para>
  75. Wärend das Konzept eines Benutzers als Rolle recht gerade heraus ist, könnte die
  76. Anwendung ein anderes Modell wählen welches im eigenen System als potentielle
  77. "Ressource" im <acronym>ACL</acronym> System verwendet wird. Der Einfachheit halber
  78. verwenden wir das Beispiel eines Blog Posts. Da der Typ der Ressource mit dem Typ des
  79. Objekts verknüpft ist, gibt diese Klasse nur 'blogPost' als Ressource ID im System
  80. zurück. Natürlich kann dieser Wert dynamisch sein wenn das System dies benötigt.
  81. </para>
  82. <programlisting language="php"><![CDATA[
  83. class Default_Model_BlogPost implements Zend_Acl_Resource_Interface
  84. {
  85. public function getResourceId()
  86. {
  87. return 'blogPost';
  88. }
  89. }
  90. ]]></programlisting>
  91. <para>
  92. Jetzt da wir zumindest eine Rolle und eine Ressource haben können wir mit der Definition
  93. der Regeln des <acronym>ACL</acronym> Systems weitermachen. Diese Regeln werden
  94. konsultiert wenn das System eine Abfrage darüber erhält was möglicherweise eine
  95. bestimmte Rolle, eine Ressource und optional ein Privileg ist.
  96. </para>
  97. <para>
  98. Nehmen wir die folgenden Regeln an:
  99. </para>
  100. <programlisting language="php"><![CDATA[
  101. $acl = new Zend_Acl();
  102. // Die verschiedenen Rollen im System einstellen
  103. $acl->addRole('guest');
  104. // Der Eigentümer erbt alle Regeln vom Gast
  105. $acl->addRole('owner', 'guest');
  106. // Die Ressource hinzufügen
  107. $acl->addResource('blogPost');
  108. // Die Privilegien den Rollen- und Ressourcekombinationen hinzufügen
  109. $acl->allow('guest', 'blogPost', 'view');
  110. $acl->allow('owner', 'blogPost', 'post');
  111. $acl->allow('owner', 'blogPost', 'publish');
  112. ]]></programlisting>
  113. <para>
  114. Die oben stehenden Regeln sund recht einfach: eine Gastrolle und eine Eigentümerrolle
  115. existieren; sowie ein blogPost Ressourcetyp. Gästen ist es erlaubt Blogposts anzusehen,
  116. und Eigentümern ist es erlaubt zu posten und Blogposts zu veröffentlichen. Um dieses
  117. System abzufragen könnte man das folgende machen:
  118. </para>
  119. <programlisting language="php"><![CDATA[
  120. // Wir nehmen an dass das Benutzermodell vom Ressourcetyp Gast ist
  121. $guestUser = new Default_Model_User();
  122. $ownerUser = new Default_Model_Owner('OwnersUsername');
  123. $post = new Default_Model_BlogPost();
  124. $acl->isAllowed($guestUser, $post, 'view'); // true
  125. $acl->isAllowed($ownerUser, $post, 'view'); // true
  126. $acl->isAllowed($guestUser, $post, 'post'); // false
  127. $acl->isAllowed($ownerUser, $post, 'post'); // true
  128. ]]></programlisting>
  129. <para>
  130. Wie man sieht können bei Ausführung der obigen Regeln entweder Eigentümer und Gäste
  131. Posts ansehen, oder neue Posts erstellen, was Eigentümer können und Gäste nicht. Aber
  132. wie man erwarten kann ist diese Art von System nicht so dynamisch wie man es wünschen
  133. könnte. Was, wenn wir sicherstellen wollen das einem spezifischen Benutzer ein sehr
  134. spezifischer Blogpost gehört bevor Ihm erlaubt wird Ihn zu veröffentlichen? In anderen
  135. Worten wollen wir sicherstellen das nur Blogpost Eigentümer nur die Möglichkeit haben
  136. Ihre eigenen Posts zu veröffentlichen.
  137. </para>
  138. <para>
  139. Hier kommen Annahmen zum Einsatz. Annahmen sind Methoden welche aufgerufen werden wenn
  140. das prüfen einer statischen Regel einfach nicht genug ist. Wenn ein Annahmeobjekt
  141. registriert wird, dann wird dieses Objekt konsultiert um, typischerweise dynamisch, zu
  142. ermitteln ob einige Rollen Zugriff auf einige Ressourcen, mit einigen optionalen
  143. Privilegien haben was nur durch die Logik in der Annahme beantwortet werden kann.
  144. Für dieses Beispiel verwenden wir die folgende Annahme:
  145. </para>
  146. <programlisting language="php"><![CDATA[
  147. class OwnerCanPublishBlogPostAssertion implements Zend_Acl_Assert_Interface
  148. {
  149. /**
  150. * Diese Annahme sollte die aktuellen Benutzer und BlogPost Objekte
  151. * empfangen
  152. *
  153. * @param Zend_Acl $acl
  154. * @param Zend_Acl_Role_Interface $user
  155. * @param Zend_Acl_Resource_Interface $blogPost
  156. * @param $privilege
  157. * @return bool
  158. */
  159. public function assert(Zend_Acl $acl,
  160. Zend_Acl_Role_Interface $user = null,
  161. Zend_Acl_Resource_Interface $blogPost = null,
  162. $privilege = null)
  163. {
  164. if (!$user instanceof Default_Model_User) {
  165. throw new Exception(__CLASS__
  166. . '::'
  167. . __METHOD__
  168. . ' erwartet das die Rolle eine'
  169. . ' Instanz von user ist');
  170. }
  171. if (!$blogPost instanceof Default_Model_BlogPost) {
  172. throw new Exception(__CLASS__
  173. . '::'
  174. . __METHOD__
  175. . ' erwartet das die Ressource eine'
  176. . ' Instanz von BlogPost ist');
  177. }
  178. // Wenn die Rolle ein publisher ist kann Sie einen Post immer verändern
  179. if ($user->getRoleId() == 'publisher') {
  180. return true;
  181. }
  182. // Prüfen um sicherzustellen das alle anderen nur deren eigene Posts
  183. // verändern
  184. if ($user->id != null && $blogPost->ownerUserId == $user->id) {
  185. return true;
  186. } else {
  187. return false;
  188. }
  189. }
  190. }
  191. ]]></programlisting>
  192. <para>
  193. Um dies mit unserem <acronym>ACL</acronym> System zu verknüpfen würden wir das folgende
  194. tun:
  195. </para>
  196. <programlisting language="php"><![CDATA[
  197. // Dies ersetzen:
  198. // $acl->allow('owner', 'blogPost', 'publish');
  199. // Mit diesem:
  200. $acl->allow('owner',
  201. 'blogPost',
  202. 'publish',
  203. new OwnerCanPublishBlogPostAssertion());
  204. // Auch die Rolle"publisher" hinzufügen der auf alles Zugriff hat
  205. $acl->allow('publisher', 'blogPost', 'publish');
  206. ]]></programlisting>
  207. <para>
  208. Jetzt wird jedesmal wenn <acronym>ACL</acronym> darüber konsultiert wird ob ein
  209. Benutzer einen spezifischen Blogpost veröffentlichen kann diese Annahme ausgeführt.
  210. Diese Annahme stellt sicher dass, solange der Rollentyp nicht 'publisher' ist, die
  211. Benutzerrolle der Anfrage logisch mit dem Blogpost verbunden sein muss. In diesem
  212. Beispiel haben wir geprüft das die Eigenschaft <property>ownerUserId</property> des
  213. Blogposts mit der übergebenen Id des Benutzers übereinstimmt.
  214. </para>
  215. </sect2>
  216. </sect1>