1 <?xml version="1.0" encoding="UTF-8"?>
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>
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
20 Dostępne opcje konfiguracyjne to:
26 <emphasis>tableName</emphasis>: Jest to nazwa tabeli bazy
27 danych, która zawiera dane uwierzytelniania i do której
28 jest przeprowadzane zapytanie uwierzytelniające.
33 <emphasis>identityColumn</emphasis>: Jest to nazwa kolumny
34 tabeli bazy danych, która reprezentuje tożsamość.
35 Kolumna tożsamości musi zawierać unikalne wartości,
36 na przykład takie jak nazwa użytkownika czy adres
42 <emphasis>credentialColumn</emphasis>: Jest to nazwa kolumny
43 tabeli bazy danych, która reprezentuje wartość
44 uwierzytelniającą. W prostym schemacie uwierzytelniania
45 opartym o nazwę tożsamości i hasło, wartość
46 uwierzytelniająca odpowiada hasłu. Zobacz także opcję
47 <emphasis>credentialTreatment</emphasis>.
52 <emphasis>credentialTreatment</emphasis>: W wielu przypadkach,
53 hasło i inne wrażliwe dane są zszyfrowane, haszowane,
54 zakodowane lub w inny sposób przetworzone przez
55 jakąś funkcję lub algorytm. Określając metodę
56 przerobienia danych, taką jak na przykład
57 'MD5(?)' czy 'PASSWORD(?)',
58 programista może użyć konkretnej funkcji SQL na danych
59 uwierzytelniających. Z tego względu, że te funkcje są
60 specyficzne dla konkretnych systemów baz danych, zajrzyj
61 do odpowiednich dokumentacji aby sprawdzić dostępność
62 takich funkcji dla twojego systemu bazy danych.
67 <example id="zend.auth.adapter.dbtable.introduction.example.basic_usage">
68 <title>Podstawowe użycie</title>
70 Jak wyjaśniono we wprowadzeniu, konstruktor klasy
71 <classname>Zend_Auth_Adapter_DbTable</classname> wymaga przekazania mu
72 instancji klasy <classname>Zend_Db_Adapter_Abstract</classname>,
73 zapewniającej połączenie do bazy danych, z którym powiązana jest
74 instancja adaptera uwierzytelniania. Na początku powinno być
75 utworzone połączenie do bazy danych.
79 Poniższy kod tworzy adapter bazy danych przechowywanej w pamięci,
80 tworzy prostą strukturę tabeli, a następnie wstawia wiersz, w
81 oparciu o który przeprowadzimy później zapytanie
82 uwierzytelniające. Ten przykład wymaga dostępnego rozszerzenia
86 <programlisting language="php"><![CDATA[
87 // Tworzymy połączenie do bazy danych SQLite przechowywanej w pamięci
88 $dbAdapter = new Zend_Db_Adapter_Pdo_Sqlite(array('dbname' =>
91 // Budujemy zapytanie tworzące prostą tabelę
92 $sqlCreate = 'CREATE TABLE [users] ('
93 . '[id] INTEGER NOT NULL PRIMARY KEY, '
94 . '[username] VARCHAR(50) UNIQUE NOT NULL, '
95 . '[password] VARCHAR(32) NULL, '
96 . '[real_name] VARCHAR(150) NULL)';
98 // Tworzymy tabelę z danymi uwierzytelniania
99 $dbAdapter->query($sqlCreate);
101 // Budujemy zapytanie wstawiające wiersz, dla którego możemy przeprowadzić
102 // próbę uwierzytelniania
103 $sqlInsert = "INSERT INTO users (username, password, real_name) "
104 . "VALUES ('my_username', 'my_password', 'My Real Name')";
107 $dbAdapter->query($sqlInsert);
111 Gdy połączenie do bazy danych oraz dane w tabeli są już
112 dostępne, możesz utworzyć instancję klasy
113 <classname>Zend_Auth_Adapter_DbTable</classname>. Opcje konfiguracyjne
114 mogą być przekazane do konstruktora lub przekazane jako
115 parametry do metod dostępowych już po utworzeniu instancji:
118 <programlisting language="php"><![CDATA[
119 // Konfigurujemy instancję za pomocą parametrów konstruktora
120 $authAdapter = new Zend_Auth_Adapter_DbTable(
127 // ...lub konfigurujemy instancję za pomocą metod dostępowych
128 $authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);
130 ->setTableName('users')
131 ->setIdentityColumn('username')
132 ->setCredentialColumn('password')
137 W tym momencie intancja adaptera uwierzytelniania jest gotowa
138 do przeprowadzenia zapytań uwierzytelniających. W celu
139 utworzenia zapytania, wejściowe dane uwierzytelniania
140 są przekazywane do adaptera przed wywołaniem metody
141 <methodname>authenticate()</methodname>:
144 <programlisting language="php"><![CDATA[
145 // Ustawiamy wartości danych uwierzytelniania (np., z formularza logowania)
147 ->setIdentity('my_username')
148 ->setCredential('my_password');
150 // Przeprowadzamy zapytanie uwierzytelniające, zapisując rezultat
151 $result = $authAdapter->authenticate();
155 Oprócz możliwości użycia metody <methodname>getIdentity()</methodname>
156 obiektu rezultatu uwierzytelniania, obiekt
157 <classname>Zend_Auth_Adapter_DbTable</classname> pozwala także na
158 odebranie wiersza tabeli po udanym uwierzytelnieniu.
161 <programlisting language="php"><![CDATA[
162 // Wyświetlamy tożsamość
163 echo $result->getIdentity() . "\n\n";
165 // Wyświetlamy wiersz rezultatów
166 print_r($authAdapter->getResultRowObject());
174 [username] => my_username
175 [password] => my_password
176 [real_name] => My Real Name
182 Z tego względu, że wiersz tabeli zawiera dane potrzebne do
183 uwierzytelniania, ważne jest, aby dane były zabezpieczone przed
184 dostępem przez osoby nieuprawnione.
189 <sect2 id="zend.auth.adapter.dbtable.advanced.storing_result_row">
190 <title>Zaawansowane użycie: Stałe przechowywanie obiektu DbTable Result</title>
192 Domyślnie <classname>Zend_Auth_Adapter_DbTable</classname> po udanym
193 uwierzytelnieniu zwraca do obiektu uwierzytelniającego spowrotem
194 tę samą tożsamość. W innym przykładzie użycia programista może
195 chcieć przechować w stałym mechanizmie przechowywania
196 <classname>Zend_Auth</classname> obiekt tożsamości zawierający inne użyteczne
197 informacje. W takim przypadku może użyć metody
198 <methodname>getResultRowObject()</methodname> aby zwrócić obiekt klasy
199 <classname>stdClass</classname>. Poniższy kod ilustruje sposób jego użycia:
202 <programlisting language="php"><![CDATA[
203 // uwierzytelniamy za pomocą Zend_Auth_Adapter_DbTable
204 $result = $this->_auth->authenticate($adapter);
206 if ($result->isValid()) {
208 // przechowujemy tożsamość jako obiekt, w którym zwracane są jedynie
209 // pola username oraz real_name
210 $storage = $this->_auth->getStorage();
211 $storage->write($adapter->getResultRowObject(array(
216 // przechowujemy tożsamość jako obiekt, w którym kolumna zawierająca
217 // hasło została pominięta
218 $storage->write($adapter->getResultRowObject(
232 <sect2 id="zend.auth.adapter.dbtable.advanced.advanced_usage">
233 <title>Przykład zaawansowanego użycia</title>
235 O ile głównym przeznaczeniem komponentu <classname>Zend_Auth</classname>
236 (i odpowiednio <classname>Zend_Auth_Adapter_DbTable</classname>) jest
237 <emphasis>uwierzytelnianie</emphasis> a nie <emphasis>autoryzacja</emphasis>,
238 jest kilka problemów które możemy rozwiązać odrobinę przekraczając
239 pole zastosowań komponentu. Zależnie od tego jak zdecydujesz
240 wyjaśnić swój problem, czasem może być przydatne rozwiązanie
241 problemu autoryzacji podczas uwierzytelniania.
245 Komponent <classname>Zend_Auth_Adapter_DbTable</classname> posiada
246 pewien wbudowany mechanizm, który może być użyty do dodania dodatkowych
247 warunków podczas uwierzytelniania, dzięki czemu można rozwiązać niektóre
251 <programlisting language="php"><![CDATA[
252 // Wartość pola "status" dla tego konta nie jest równa wartości "compromised"
253 $adapter = new Zend_Auth_Adapter_DbTable(
258 'MD5(?) AND status != "compromised"'
261 // Wartość pola "active" dla tego konta jest równa wartości "TRUE"
262 $adapter = new Zend_Auth_Adapter_DbTable(
267 'MD5(?) AND active = "TRUE"'
272 Innym przykładem może być implementacja mechanizmu saltingu. Jest to
273 technika pozwalająca w znaczny sposób zwiększyć bezpieczeństwo
274 aplikacji. Polega ona na tym, że dołączając do każdego hasła losowy
275 łańcuch znaków spowodujemy, że niemożliwe będzie przeprowadzenie
276 ataku brute force na bazę danych w oparciu o przygotowany słownik.
280 Zaczniemy od zmodyfikowania schematu tabeli bazy danych, aby móc
281 przechowywać nasz łańcuch znaków salt:
284 <programlisting language="php"><![CDATA[
285 $sqlAlter = "ALTER TABLE [users] "
286 . "ADD COLUMN [password_salt] "
287 . "AFTER [password]";
289 $dbAdapter->query($sqlAlter);
293 W prosty sposób wygenerujmy salt dla każdego rejestrującego się
297 <programlisting language="php"><![CDATA[
298 for ($i = 0; $i < 50; $i++)
300 $dynamicSalt .= chr(rand(33, 126));
305 I skonfigurujmy sterownik bazy danych:
308 <programlisting language="php"><![CDATA[
309 $adapter = new Zend_Auth_Adapter_DbTable(
315 . Zend_Registry::get('staticSalt')
316 . "', ?, password_salt))"
321 Możesz jeszcze zwiększyć bezpieczeństwo używając dodatkowo
322 statycznego fragmentu łańcucha znaków umieszczonego na stałe
323 w kodzie aplikacji. W przypadku, gdy atakujący uzyska dostęp
324 do bazy danych (np. za pomocą ataku <acronym>SQL</acronym>
325 injection), a nie będzie miał dostępu do kodu źródłowego,
326 hasła wciąż będą dla niego nieprzydatne.
331 Innym sposobem jest użycie metody <methodname>getDbSelect()</methodname>
332 klasy <classname>Zend_Auth_Adapter_DbTable</classname> po utworzeniu
333 adaptera. Ta metoda zwróci obiekt klasy <classname>Zend_Db_Select</classname>,
334 który ma być użyty do przeprowadzenia uwierzytalniania. Ważne jest, że
335 ta metoda zawsze zwróci ten sam obiekt, niezależnie od tego czy metoda
336 <methodname>authenticate()</methodname> została wywołana czy nie.
337 Ten obiekt <emphasis>nie będzie</emphasis> posiadał żadnych informacji
338 dotyczących nazwy tożsamości i hasła, ponieważ te dane będą umieszczone
339 tam dopiero w czasie wywołania metody <methodname>authenticate()</methodname>.
343 Przykładem sytuacji w której można by użyć metody getDbSelect()
344 może być potrzeba sprawdzenia statusu użytkownika, czyli sprawdzenia
345 czy konto użytkownika jest aktywne.
348 <programlisting language="php"><![CDATA[
349 // Kontynuując poprzedni przykład
350 $adapter = new Zend_Auth_Adapter_DbTable(
358 // pobieramy obiekt Zend_Db_Select (przez referencję)
359 $select = $adapter->getDbSelect();
360 $select->where('active = "TRUE"');
362 // uwierytelniamy, z warunkiem users.active = TRUE
363 $adapter->authenticate();