Zend_Auth_Adapter_DbTable.xml 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <!-- EN-Revision: 24249 -->
  3. <!-- Reviewed: no -->
  4. <sect1 id="zend.auth.adapter.dbtable">
  5. <title>Authentification avec une table de base de données</title>
  6. <sect2 id="zend.auth.adapter.dbtable.introduction">
  7. <title>Introduction</title>
  8. <para>
  9. <classname>Zend_Auth_Adapter_DbTable</classname> fournit la possibilité d'authentifier
  10. sur la base de crédits stockés dans une table de base de données. Comme
  11. <classname>Zend_Auth_Adapter_DbTable</classname> requiert qu'une instance de
  12. <classname>Zend_Db_Adapter_Abstract</classname> soit fournie à son constructeur, chaque
  13. instance est liée à une connexion de base de données particulière. Les autres options
  14. de configuration peuvent être réglées grâce au constructeur ou au travers de
  15. différentes méthodes, une pour chaque option.
  16. </para>
  17. <para>
  18. Les options de configuration disponibles incluent&#160;:
  19. </para>
  20. <itemizedlist>
  21. <listitem>
  22. <para>
  23. <emphasis><property>tableName</property></emphasis>&#160;: il s'agit du nom de
  24. la table dans la base de données qui contient les crédits d'authentification,
  25. et envers laquelle la requête d'authentification sera réalisée.
  26. </para>
  27. </listitem>
  28. <listitem>
  29. <para>
  30. <emphasis><property>identityColumn</property></emphasis>&#160;: il s'agit du
  31. nom de la colonne dans la table utilisée pour représenter l'identité. La
  32. colonne d'identité doit contenir une valeur unique, comme un "username" ou
  33. une adresse mail.
  34. </para>
  35. </listitem>
  36. <listitem>
  37. <para>
  38. <emphasis><property>credentialColumn</property></emphasis>&#160;: il s'agit
  39. du nom de la colonne dans la table utilisée pour représenter le crédit. Dans
  40. le cas d'une simple authentification par identité / mot de passe, la valeur
  41. de crédit correspond au mot de passe. Voir aussi l'option
  42. <property>credentialTreatment</property>.
  43. </para>
  44. </listitem>
  45. <listitem>
  46. <para>
  47. <emphasis><property>credentialTreatment</property></emphasis>&#160;: dans la
  48. plupart des cas, les mots de passe et autres données sensibles sont cryptés,
  49. hachés, encodés, masqués, ou sinon traités à travers une fonction ou un
  50. algorithme. En spécifiant un traitement paramétrable de chaîne avec cette
  51. méthode, comme <methodname>MD5(?)</methodname> ou
  52. <methodname>PASSWORD(?)</methodname>, un
  53. développeur peut appliquer un code <acronym>SQL</acronym> arbitraire sur les
  54. données de crédit fournies. Comme ces fonctions sont spécifiques à chaque
  55. gestionnaire de base de données (<acronym>SGBD</acronym>), vérifiez le manuel
  56. de la base de données pour vérifier la disponibilité de ces fonctions dans
  57. votre système.
  58. </para>
  59. </listitem>
  60. </itemizedlist>
  61. <example id="zend.auth.adapter.dbtable.introduction.example.basic_usage">
  62. <title>Utilisation basique</title>
  63. <para>
  64. Comme expliqué dans l'introduction, le constructeur de
  65. <classname>Zend_Auth_Adapter_DbTable</classname> requiert une instance de
  66. <classname>Zend_Db_Adapter_Abstract</classname> qui est utilisée comme connexion à
  67. la base de données à laquelle l'instance d'adaptateur d'authentification est liée.
  68. Avant tout, la connexion à la base de donnée devrait être crée.
  69. </para>
  70. <para>
  71. Le code suivant crée un adaptateur pour une base de données en mémoire, crée
  72. un schéma avec une table unique, et insère une ligne sur laquelle nous pouvons
  73. réaliser une requête d'authentification plus tard. Cet exemple requiert que
  74. l'extension <acronym>PDO</acronym> SQLite soit disponible&#160;:
  75. </para>
  76. <programlisting language="php"><![CDATA[
  77. // Crée une connexion de base de données SQLite en mémoire
  78. $dbAdapter = new Zend_Db_Adapter_Pdo_Sqlite(array('dbname' =>
  79. ':memory:'));
  80. // Construit une requête de création de table
  81. $sqlCreate = 'CREATE TABLE [users] ( '
  82. . '[id] INTEGER NOT NULL PRIMARY KEY, '
  83. . '[username] VARCHAR(50) UNIQUE NOT NULL, '
  84. . '[password] VARCHAR(32) NULL, '
  85. . '[real_name] VARCHAR(150) NULL)';
  86. // Crée la table de crédits d'authentification
  87. $dbAdapter->query($sqlCreate);
  88. // Construit la requête pour insérer une ligne pour laquelle
  89. // l'authentification pourra réussir
  90. $sqlInsert = "INSERT INTO users (username, password, real_name) "
  91. . "VALUES ('my_username', 'my_password', 'My Real Name')";
  92. // Insertion des données
  93. $dbAdapter->query($sqlInsert);
  94. ]]></programlisting>
  95. <para>
  96. Avec une connexion de base de données et des données disponibles dans la
  97. table, une instance de <classname>Zend_Auth_Adapter_DbTable</classname> peut être
  98. créée. Les valeurs d'options de configuration peuvent être fournies au
  99. constructeur ou en tant que paramètres aux méthodes de réglage après
  100. l'instanciation&#160;:
  101. </para>
  102. <programlisting language="php"><![CDATA[
  103. // Configure une instance avec des paramètres de constructeur ...
  104. $authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter,
  105. 'users',
  106. 'username',
  107. 'password');
  108. // ... ou configure l'instance avec des méthodes de réglage
  109. $authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);
  110. $authAdapter->setTableName('users')
  111. ->setIdentityColumn('username')
  112. ->setCredentialColumn('password');
  113. ]]></programlisting>
  114. <para>
  115. A cet instant, l'instance de l'adaptateur d'authentification est prête à
  116. recevoir des requêtes d'authentification. Dans le but de réaliser une requête
  117. d'authentification, les valeurs des crédits requêtés sont fournies à l'adaptateur
  118. avant d'appeler la méthode <methodname>authenticate()</methodname>&#160;:
  119. </para>
  120. <programlisting language="php"><![CDATA[
  121. // Règle les valeurs d'entrées des crédits
  122. // (en général, à partir d'un formulaire d'enregistrement)
  123. $authAdapter->setIdentity('my_username')
  124. ->setCredential('my_password');
  125. // Réalise la requête d'authentification, et sauvegarde le résultat
  126. $result = $authAdapter->authenticate();
  127. ]]></programlisting>
  128. <para>
  129. En plus de la disponibilité de la méthode <methodname>getIdentity()</methodname>
  130. pour récupérer l'objet du résultat d'authentification,
  131. <classname>Zend_Auth_Adapter_DbTable</classname> supporte aussi la récupération de
  132. la ligne de la table qui a réussi l'authentification&#160;:
  133. </para>
  134. <programlisting language="php"><![CDATA[
  135. // Affiche l'identité
  136. echo $result->getIdentity() . "\n\n";
  137. // Affiche la ligne de résultat
  138. print_r($authAdapter->getResultRowObject());
  139. /* Affiche:
  140. my_username
  141. Array
  142. (
  143. [id] => 1
  144. [username] => my_username
  145. [password] => my_password
  146. [real_name] => My Real Name
  147. )
  148. */
  149. ]]></programlisting>
  150. <para>
  151. Puisque la ligne de la table contient la valeur de crédit, il est important de
  152. garantir ces valeurs contre l'accès fortuit.
  153. </para>
  154. </example>
  155. </sect2>
  156. <sect2 id="zend.auth.adapter.dbtable.advanced.storing_result_row">
  157. <title>Utilisation avancée : maintenir persistant l'objet de résultat DbTable</title>
  158. <para>
  159. Par défaut, <classname>Zend_Auth_Adapter_DbTable</classname> retourne l'identité
  160. fournie à l'objet Auth en cas d'authentification couronnée de succès. Un autre scénario
  161. d'utilisation, où les développeurs veulent stocker dans le mécanisme de stockage
  162. persistant du <classname>Zend_Auth</classname> un objet d'identité contenant d'autres
  163. informations utiles, est résolu en utilisant la méthode
  164. <methodname>getResultRowObject()</methodname> retournant un objet
  165. <emphasis>stdClass</emphasis>. Le petit bout de code suivant illustre cette
  166. utilisation&#160;:
  167. </para>
  168. <programlisting language="php"><![CDATA[
  169. // authentifie avec Zend_Auth_Adapter_DbTable
  170. $result = $this->_auth->authenticate($adapter);
  171. if ($result->isValid()) {
  172. // stocke l'identité comme objet dans lequel seulement username et
  173. // real_name sont retournés
  174. $storage = $this->_auth->getStorage();
  175. $storage->write($adapter->getResultRowObject(array('username',
  176. 'real_name')));
  177. // stocke l'identité comme objet dans lequel la colonne password
  178. // a été omis
  179. $storage->write($adapter->getResultRowObject(null, 'password'));
  180. /* ... */
  181. } else {
  182. /* ... */
  183. }
  184. ]]></programlisting>
  185. </sect2>
  186. <sect2 id="zend.auth.adapter.dbtable.advanced.advanced_usage">
  187. <title>Utilisation avancée par l'exemple</title>
  188. <para>
  189. Bien que le but initial de <classname>Zend_Auth</classname> (et par extension celui de
  190. <classname>Zend_Auth_Adapter_DbTable</classname>) est principalement
  191. l'<emphasis>authentification</emphasis> et non
  192. l'<emphasis>autorisation</emphasis> (ou contrôle d'accès), il existe quelques
  193. exemples et problèmes qui franchissent la limite des domaines auxquels ils
  194. appartiennent. Selon la façon dont vous avez décidé d'expliquer votre problème, il
  195. semble parfois raisonnable de résoudre ce qui pourrait ressembler à un problème
  196. d'autorisation dans l'adaptateur d'authentification.
  197. </para>
  198. <para>
  199. Ceci étant dit, <classname>Zend_Auth_Adapter_DbTable</classname> possède des mécanismes
  200. qui sont construits de telle sorte qu'ils peuvent être démultipliés pour ajouter des
  201. contrôles supplémentaires au moment de l'authentification pour résoudre quelques
  202. problèmes communs d'utilisateur.
  203. </para>
  204. <programlisting language="php"><![CDATA[
  205. // La valeur du champs "etat" d'un compte
  206. // ne doit pas être égal à "compromis"
  207. $adapter = new Zend_Auth_Adapter_DbTable($db,
  208. 'utilisateurs',
  209. 'login',
  210. 'password',
  211. 'MD5(?) AND etat != "compromis"');
  212. // La valeur du champs "actif" d'un compte
  213. // doit être égal à "TRUE"
  214. $adapter = new Zend_Auth_Adapter_DbTable($db,
  215. 'utilisateurs',
  216. 'login',
  217. 'password',
  218. 'MD5(?) AND actif = "TRUE"');
  219. ]]></programlisting>
  220. <para>
  221. Un autre scénario possible est l'implantation d'un mécanisme de "salting".
  222. "Salting" est un terme se référant une technique qui peut fortement améliorer la
  223. sécurité de votre application. C'est basé sur l'idée que concaténer une chaîne
  224. aléatoire à tout mot de passe rend impossible la réussite d'une attaque de type "brute
  225. force" sur la base de données en utilisant des valeurs préalablement hashées issues
  226. d'un dictionnaire.
  227. </para>
  228. <para>
  229. Par conséquent nous devons modifier notre table pour stocker notre chaîne de
  230. "salt" aléatoire&#160;:
  231. </para>
  232. <programlisting language="php"><![CDATA[
  233. $sqlAlter = "ALTER TABLE [users] "
  234. . "ADD COLUMN [password_salt] "
  235. . "AFTER [password]";
  236. $dbAdapter->query($sqlAlter);
  237. ]]></programlisting>
  238. <para>
  239. Voici une méthode simple pour générer une chaîne aléatoire pour chaque
  240. utilisateur à leur enregistrement&#160;:
  241. </para>
  242. <programlisting language="php"><![CDATA[
  243. for ($i = 0; $i < 50; $i++)
  244. {
  245. $dynamicSalt .= chr(rand(33, 126));
  246. }
  247. ]]></programlisting>
  248. <para>Et maintenant, construisons l'adaptateur&#160;:</para>
  249. <programlisting language="php"><![CDATA[
  250. $adapter = new Zend_Auth_Adapter_DbTable(
  251. $db,
  252. 'users',
  253. 'username',
  254. 'password',
  255. "MD5(CONCAT('"
  256. . Zend_Registry::get('staticSalt')
  257. . "', ?, password_salt))"
  258. );
  259. ]]></programlisting>
  260. <note>
  261. <para>
  262. Vous pouvez encore améliorer la sécurité en utilisant une chaîne de "salt"
  263. statique codée en dur dans votre application. Dans le cas ou la base de données est
  264. compromise (par exemple par une attaque de type injection <acronym>SQL</acronym>)
  265. mais que votre serveur Web est intact, les données sont inutilisables par
  266. l'attaquant.
  267. </para>
  268. </note>
  269. <para>
  270. Une autre alternative est d'utiliser la méthode <methodname>getDbSelect()</methodname>
  271. de la classe <classname>Zend_Auth_Adapter_DbTable</classname> après la construction de
  272. l'adaptateur. Cette méthode retournera une instance d'objet
  273. <classname>Zend_Db_Select</classname> utilisée pour réaliser la routine
  274. <methodname>authenticate()</methodname>. Il est important de noter que cette méthode
  275. retournera toujours le même objet, que la méthode
  276. <methodname>authenticate()</methodname> a été appelée ou non. Cet objet
  277. <emphasis>ne comportera aucune</emphasis> information d'identité ou de crédit puisque
  278. celles-ci sont placées dans l'objet select au moment de
  279. <methodname>authenticate()</methodname>.
  280. </para>
  281. <para>
  282. Un exemple de situation nécessitant l'utilisation de la méthode
  283. <methodname>getDbSelect()</methodname> serait de vérifier le statut d'un utilisateur,
  284. en d'autres termes pour voir si le compte d'un utilisateur est activé.
  285. </para>
  286. <programlisting language="php"><![CDATA[
  287. // En continuant avec l'exemple ci-dessus
  288. $adapter = new Zend_Auth_Adapter_DbTable(
  289. $db,
  290. 'users',
  291. 'username',
  292. 'password',
  293. 'MD5(?)'
  294. );
  295. // Récupérer l'objet select (par référence)
  296. $select = $adapter->getDbSelect();
  297. $select->where('active = "TRUE"');
  298. // Authentification, ceci s'assure que users.active = TRUE
  299. $adapter->authenticate();
  300. ]]></programlisting>
  301. </sect2>
  302. </sect1>