Zend_Auth_Adapter_DbTable.xml 13 KB

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