multiuser-authorization.xml 10 KB

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