Zend_Auth_Adapter_DbTable.xml 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- Reviewed: no -->
  3. <sect1 id="zend.auth.adapter.dbtable">
  4. <title>Uwierzytelnianie w oparciu o tabelę bazy danych</title>
  5. <sect2 id="zend.auth.adapter.dbtable.introduction">
  6. <title>Wprowadzenie</title>
  7. <para>
  8. <classname>Zend_Auth_Adapter_DbTable</classname> zapewnia możliwość
  9. przeprowadzenia uwierzytelniania w oparciu o dane przechowywane w
  10. tabeli bazy danych. Z tego względu, że klasa
  11. <classname>Zend_Auth_Adapter_DbTable</classname> wymaga przekazania instancji
  12. klasy <classname>Zend_Db_Adapter_Abstract</classname> do jej konstruktora,
  13. każda ta instancja jest powiązana z konkretnym połączeniem do bazy
  14. danych. Inne opcje konfiguracyjne mogą być ustawione za pomocą
  15. konstruktora lub za pomocą metod instancji, po jednej dla każdej z
  16. opcji.
  17. </para>
  18. <para>
  19. Dostępne opcje konfiguracyjne to:
  20. </para>
  21. <itemizedlist>
  22. <listitem>
  23. <para>
  24. <emphasis>tableName</emphasis>: Jest to nazwa tabeli bazy
  25. danych, która zawiera dane uwierzytelniania i do której
  26. jest przeprowadzane zapytanie uwierzytelniające.
  27. </para>
  28. </listitem>
  29. <listitem>
  30. <para>
  31. <emphasis>identityColumn</emphasis>: Jest to nazwa kolumny
  32. tabeli bazy danych, która reprezentuje tożsamość.
  33. Kolumna tożsamości musi zawierać unikalne wartości,
  34. na przykład takie jak nazwa użytkownika czy adres
  35. e-mail.
  36. </para>
  37. </listitem>
  38. <listitem>
  39. <para>
  40. <emphasis>credentialColumn</emphasis>: Jest to nazwa kolumny
  41. tabeli bazy danych, która reprezentuje wartość
  42. uwierzytelniającą. W prostym schemacie uwierzytelniania
  43. opartym o nazwę tożsamości i hasło, wartość
  44. uwierzytelniająca odpowiada hasłu. Zobacz także opcję
  45. <emphasis>credentialTreatment</emphasis>.
  46. </para>
  47. </listitem>
  48. <listitem>
  49. <para>
  50. <emphasis>credentialTreatment</emphasis>: W wielu przypadkach,
  51. hasło i inne wrażliwe dane są zszyfrowane, haszowane,
  52. zakodowane lub w inny sposób przetworzone przez
  53. jakąś funkcję lub algorytm. Określając metodę
  54. przerobienia danych, taką jak na przykład
  55. 'MD5(?)' czy 'PASSWORD(?)',
  56. programista może użyć konkretnej funkcji SQL na danych
  57. uwierzytelniających. Z tego względu, że te funkcje są
  58. specyficzne dla konkretnych systemów baz danych, zajrzyj
  59. do odpowiednich dokumentacji aby sprawdzić dostępność
  60. takich funkcji dla twojego systemu bazy danych.
  61. </para>
  62. </listitem>
  63. </itemizedlist>
  64. <example id="zend.auth.adapter.dbtable.introduction.example.basic_usage">
  65. <title>Podstawowe użycie</title>
  66. <para>
  67. Jak wyjaśniono we wprowadzeniu, konstruktor klasy
  68. <classname>Zend_Auth_Adapter_DbTable</classname> wymaga przekazania mu
  69. instancji klasy <classname>Zend_Db_Adapter_Abstract</classname>,
  70. zapewniającej połączenie do bazy danych, z którym powiązana jest
  71. instancja adaptera uwierzytelniania. Na początku powinno być
  72. utworzone połączenie do bazy danych.
  73. </para>
  74. <para>
  75. Poniższy kod tworzy adapter bazy danych przechowywanej w pamięci,
  76. tworzy prostą strukturę tabeli, a następnie wstawia wiersz, w
  77. oparciu o który przeprowadzimy później zapytanie
  78. uwierzytelniające. Ten przykład wymaga dostępnego rozszerzenia
  79. PDO SQLite:
  80. </para>
  81. <programlisting language="php"><![CDATA[
  82. // Tworzymy połączenie do bazy danych SQLite przechowywanej w pamięci
  83. $dbAdapter = new Zend_Db_Adapter_Pdo_Sqlite(array('dbname' =>
  84. ':memory:'));
  85. // Budujemy zapytanie tworzące prostą tabelę
  86. $sqlCreate = 'CREATE TABLE [users] ('
  87. . '[id] INTEGER NOT NULL PRIMARY KEY, '
  88. . '[username] VARCHAR(50) UNIQUE NOT NULL, '
  89. . '[password] VARCHAR(32) NULL, '
  90. . '[real_name] VARCHAR(150) NULL)';
  91. // Tworzymy tabelę z danymi uwierzytelniania
  92. $dbAdapter->query($sqlCreate);
  93. // Budujemy zapytanie wstawiające wiersz, dla którego możemy przeprowadzić
  94. // próbę uwierzytelniania
  95. $sqlInsert = "INSERT INTO users (username, password, real_name) "
  96. . "VALUES ('my_username', 'my_password', 'My Real Name')";
  97. // Wstawiamy dane
  98. $dbAdapter->query($sqlInsert);
  99. ]]></programlisting>
  100. <para>
  101. Gdy połączenie do bazy danych oraz dane w tabeli są już
  102. dostępne, możesz utworzyć instancję klasy
  103. <classname>Zend_Auth_Adapter_DbTable</classname>. Opcje konfiguracyjne
  104. mogą być przekazane do konstruktora lub przekazane jako
  105. parametry do metod dostępowych już po utworzeniu instancji:
  106. </para>
  107. <programlisting language="php"><![CDATA[
  108. // Konfigurujemy instancję za pomocą parametrów konstruktora
  109. $authAdapter = new Zend_Auth_Adapter_DbTable(
  110. $dbAdapter,
  111. 'users',
  112. 'username',
  113. 'password'
  114. );
  115. // ...lub konfigurujemy instancję za pomocą metod dostępowych
  116. $authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);
  117. $authAdapter
  118. ->setTableName('users')
  119. ->setIdentityColumn('username')
  120. ->setCredentialColumn('password')
  121. ;
  122. ]]></programlisting>
  123. <para>
  124. W tym momencie intancja adaptera uwierzytelniania jest gotowa
  125. do przeprowadzenia zapytań uwierzytelniających. W celu
  126. utworzenia zapytania, wejściowe dane uwierzytelniania
  127. są przekazywane do adaptera przed wywołaniem metody
  128. <methodname>authenticate()</methodname>:
  129. </para>
  130. <programlisting language="php"><![CDATA[
  131. // Ustawiamy wartości danych uwierzytelniania (np., z formularza logowania)
  132. $authAdapter
  133. ->setIdentity('my_username')
  134. ->setCredential('my_password');
  135. // Przeprowadzamy zapytanie uwierzytelniające, zapisując rezultat
  136. $result = $authAdapter->authenticate();
  137. ]]></programlisting>
  138. <para>
  139. Oprócz możliwości użycia metody <methodname>getIdentity()</methodname>
  140. obiektu rezultatu uwierzytelniania, obiekt
  141. <classname>Zend_Auth_Adapter_DbTable</classname> pozwala także na
  142. odebranie wiersza tabeli po udanym uwierzytelnieniu.
  143. </para>
  144. <programlisting language="php"><![CDATA[
  145. // Wyświetlamy tożsamość
  146. echo $result->getIdentity() . "\n\n";
  147. // Wyświetlamy wiersz rezultatów
  148. print_r($authAdapter->getResultRowObject());
  149. /* Wyświetlone dane:
  150. my_username
  151. Array
  152. (
  153. [id] => 1
  154. [username] => my_username
  155. [password] => my_password
  156. [real_name] => My Real Name
  157. )
  158. */
  159. ]]></programlisting>
  160. <para>
  161. Z tego względu, że wiersz tabeli zawiera dane potrzebne do
  162. uwierzytelniania, ważne jest, aby dane były zabezpieczone przed
  163. dostępem przez osoby nieuprawnione.
  164. </para>
  165. </example>
  166. </sect2>
  167. <sect2 id="zend.auth.adapter.dbtable.advanced.storing_result_row">
  168. <title>Zaawansowane użycie: Stałe przechowywanie obiektu DbTable Result</title>
  169. <para>
  170. Domyślnie <classname>Zend_Auth_Adapter_DbTable</classname> po udanym
  171. uwierzytelnieniu zwraca do obiektu uwierzytelniającego spowrotem
  172. tę samą tożsamość. W innym przykładzie użycia programista może
  173. chcieć przechować w stałym mechanizmie przechowywania
  174. <classname>Zend_Auth</classname> obiekt tożsamości zawierający inne użyteczne
  175. informacje. W takim przypadku może użyć metody
  176. <methodname>getResultRowObject()</methodname> aby zwrócić obiekt klasy
  177. <classname>stdClass</classname>. Poniższy kod ilustruje sposób jego użycia:
  178. </para>
  179. <programlisting language="php"><![CDATA[
  180. // uwierzytelniamy za pomocą Zend_Auth_Adapter_DbTable
  181. $result = $this->_auth->authenticate($adapter);
  182. if ($result->isValid()) {
  183. // przechowujemy tożsamość jako obiekt, w którym zwracane są jedynie
  184. // pola username oraz real_name
  185. $storage = $this->_auth->getStorage();
  186. $storage->write($adapter->getResultRowObject(array(
  187. 'username',
  188. 'real_name'
  189. )));
  190. // przechowujemy tożsamość jako obiekt, w którym kolumna zawierająca
  191. // hasło została pominięta
  192. $storage->write($adapter->getResultRowObject(
  193. null,
  194. 'password'
  195. ));
  196. /* ... */
  197. } else {
  198. /* ... */
  199. }
  200. ]]></programlisting>
  201. </sect2>
  202. <sect2 id="zend.auth.adapter.dbtable.advanced.advanced_usage">
  203. <title>Przykład zaawansowanego użycia</title>
  204. <para>
  205. O ile głównym przeznaczeniem komponentu <classname>Zend_Auth</classname>
  206. (i odpowiednio <classname>Zend_Auth_Adapter_DbTable</classname>) jest
  207. <emphasis>uwierzytelnianie</emphasis> a nie <emphasis>autoryzacja</emphasis>,
  208. jest kilka problemów które możemy rozwiązać odrobinę przekraczając
  209. pole zastosowań komponentu. Zależnie od tego jak zdecydujesz
  210. wyjaśnić swój problem, czasem może być przydatne rozwiązanie
  211. problemu autoryzacji podczas uwierzytelniania.
  212. </para>
  213. <para>
  214. Komponent <classname>Zend_Auth_Adapter_DbTable</classname> posiada
  215. pewien wbudowany mechanizm, który może być użyty do dodania dodatkowych
  216. warunków podczas uwierzytelniania, dzięki czemu można rozwiązać niektóre
  217. problemy.
  218. </para>
  219. <programlisting language="php"><![CDATA[
  220. // Wartość pola "status" dla tego konta nie jest równa wartości "compromised"
  221. $adapter = new Zend_Auth_Adapter_DbTable(
  222. $db,
  223. 'users',
  224. 'username',
  225. 'password',
  226. 'MD5(?) AND status != "compromised"'
  227. );
  228. // Wartość pola "active" dla tego konta jest równa wartości "TRUE"
  229. $adapter = new Zend_Auth_Adapter_DbTable(
  230. $db,
  231. 'users',
  232. 'username',
  233. 'password',
  234. 'MD5(?) AND active = "TRUE"'
  235. );
  236. ]]></programlisting>
  237. <para>
  238. Innym przykładem może być implementacja mechanizmu saltingu. Jest to
  239. technika pozwalająca w znaczny sposób zwiększyć bezpieczeństwo
  240. aplikacji. Polega ona na tym, że dołączając do każdego hasła losowy
  241. łańcuch znaków spowodujemy, że niemożliwe będzie przeprowadzenie
  242. ataku brute force na bazę danych w oparciu o przygotowany słownik.
  243. </para>
  244. <para>
  245. Zaczniemy od zmodyfikowania schematu tabeli bazy danych, aby móc
  246. przechowywać nasz łańcuch znaków salt:
  247. </para>
  248. <programlisting language="php"><![CDATA[
  249. $sqlAlter = "ALTER TABLE [users] "
  250. . "ADD COLUMN [password_salt] "
  251. . "AFTER [password]";
  252. $dbAdapter->query($sqlAlter);
  253. ]]></programlisting>
  254. <para>
  255. W prosty sposób wygenerujmy salt dla każdego rejestrującego się
  256. użytkownika:
  257. </para>
  258. <programlisting language="php"><![CDATA[
  259. for ($i = 0; $i < 50; $i++)
  260. {
  261. $dynamicSalt .= chr(rand(33, 126));
  262. }
  263. ]]></programlisting>
  264. <para>
  265. I skonfigurujmy sterownik bazy danych:
  266. </para>
  267. <programlisting language="php"><![CDATA[
  268. $adapter = new Zend_Auth_Adapter_DbTable(
  269. $db,
  270. 'users',
  271. 'username',
  272. 'password',
  273. "MD5(CONCAT('"
  274. . Zend_Registry::get('staticSalt')
  275. . "', ?, password_salt))"
  276. );
  277. ]]></programlisting>
  278. <note>
  279. <para>
  280. Możesz jeszcze zwiększyć bezpieczeństwo używając dodatkowo
  281. statycznego fragmentu łańcucha znaków umieszczonego na stałe
  282. w kodzie aplikacji. W przypadku, gdy atakujący uzyska dostęp
  283. do bazy danych (np. za pomocą ataku <acronym>SQL</acronym>
  284. injection), a nie będzie miał dostępu do kodu źródłowego,
  285. hasła wciąż będą dla niego nieprzydatne.
  286. </para>
  287. </note>
  288. <para>
  289. Innym sposobem jest użycie metody <methodname>getDbSelect()</methodname>
  290. klasy <classname>Zend_Auth_Adapter_DbTable</classname> po utworzeniu
  291. adaptera. Ta metoda zwróci obiekt klasy <classname>Zend_Db_Select</classname>,
  292. który ma być użyty do przeprowadzenia uwierzytalniania. Ważne jest, że
  293. ta metoda zawsze zwróci ten sam obiekt, niezależnie od tego czy metoda
  294. <methodname>authenticate()</methodname> została wywołana czy nie.
  295. Ten obiekt <emphasis>nie będzie</emphasis> posiadał żadnych informacji
  296. dotyczących nazwy tożsamości i hasła, ponieważ te dane będą umieszczone
  297. tam dopiero w czasie wywołania metody <methodname>authenticate()</methodname>.
  298. </para>
  299. <para>
  300. Przykładem sytuacji w której można by użyć metody getDbSelect()
  301. może być potrzeba sprawdzenia statusu użytkownika, czyli sprawdzenia
  302. czy konto użytkownika jest aktywne.
  303. </para>
  304. <programlisting language="php"><![CDATA[
  305. // Kontynuując poprzedni przykład
  306. $adapter = new Zend_Auth_Adapter_DbTable(
  307. $db,
  308. 'users',
  309. 'username',
  310. 'password',
  311. 'MD5(?)'
  312. );
  313. // pobieramy obiekt Zend_Db_Select (przez referencję)
  314. $select = $adapter->getDbSelect();
  315. $select->where('active = "TRUE"');
  316. // uwierytelniamy, z warunkiem users.active = TRUE
  317. $adapter->authenticate();
  318. ]]></programlisting>
  319. </sect2>
  320. </sect1>