| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- Reviewed: no -->
- <sect1 id="zend.auth.adapter.dbtable">
- <title>Uwierzytelnianie w oparciu o tabelę bazy danych</title>
- <sect2 id="zend.auth.adapter.dbtable.introduction">
- <title>Wprowadzenie</title>
- <para>
- <classname>Zend_Auth_Adapter_DbTable</classname> zapewnia możliwość
- przeprowadzenia uwierzytelniania w oparciu o dane przechowywane w
- tabeli bazy danych. Z tego względu, że klasa
- <classname>Zend_Auth_Adapter_DbTable</classname> wymaga przekazania instancji
- klasy <classname>Zend_Db_Adapter_Abstract</classname> do jej konstruktora,
- każda ta instancja jest powiązana z konkretnym połączeniem do bazy
- danych. Inne opcje konfiguracyjne mogą być ustawione za pomocą
- konstruktora lub za pomocą metod instancji, po jednej dla każdej z
- opcji.
- </para>
- <para>
- Dostępne opcje konfiguracyjne to:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <emphasis>tableName</emphasis>: Jest to nazwa tabeli bazy
- danych, która zawiera dane uwierzytelniania i do której
- jest przeprowadzane zapytanie uwierzytelniające.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>identityColumn</emphasis>: Jest to nazwa kolumny
- tabeli bazy danych, która reprezentuje tożsamość.
- Kolumna tożsamości musi zawierać unikalne wartości,
- na przykład takie jak nazwa użytkownika czy adres
- e-mail.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>credentialColumn</emphasis>: Jest to nazwa kolumny
- tabeli bazy danych, która reprezentuje wartość
- uwierzytelniającą. W prostym schemacie uwierzytelniania
- opartym o nazwę tożsamości i hasło, wartość
- uwierzytelniająca odpowiada hasłu. Zobacz także opcję
- <emphasis>credentialTreatment</emphasis>.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>credentialTreatment</emphasis>: W wielu przypadkach,
- hasło i inne wrażliwe dane są zszyfrowane, haszowane,
- zakodowane lub w inny sposób przetworzone przez
- jakąś funkcję lub algorytm. Określając metodę
- przerobienia danych, taką jak na przykład
- 'MD5(?)' czy 'PASSWORD(?)',
- programista może użyć konkretnej funkcji SQL na danych
- uwierzytelniających. Z tego względu, że te funkcje są
- specyficzne dla konkretnych systemów baz danych, zajrzyj
- do odpowiednich dokumentacji aby sprawdzić dostępność
- takich funkcji dla twojego systemu bazy danych.
- </para>
- </listitem>
- </itemizedlist>
- <example id="zend.auth.adapter.dbtable.introduction.example.basic_usage">
- <title>Podstawowe użycie</title>
- <para>
- Jak wyjaśniono we wprowadzeniu, konstruktor klasy
- <classname>Zend_Auth_Adapter_DbTable</classname> wymaga przekazania mu
- instancji klasy <classname>Zend_Db_Adapter_Abstract</classname>,
- zapewniającej połączenie do bazy danych, z którym powiązana jest
- instancja adaptera uwierzytelniania. Na początku powinno być
- utworzone połączenie do bazy danych.
- </para>
- <para>
- Poniższy kod tworzy adapter bazy danych przechowywanej w pamięci,
- tworzy prostą strukturę tabeli, a następnie wstawia wiersz, w
- oparciu o który przeprowadzimy później zapytanie
- uwierzytelniające. Ten przykład wymaga dostępnego rozszerzenia
- PDO SQLite:
- </para>
- <programlisting language="php"><![CDATA[
- // Tworzymy połączenie do bazy danych SQLite przechowywanej w pamięci
- $dbAdapter = new Zend_Db_Adapter_Pdo_Sqlite(array('dbname' =>
- ':memory:'));
- // Budujemy zapytanie tworzące prostą tabelę
- $sqlCreate = 'CREATE TABLE [users] ('
- . '[id] INTEGER NOT NULL PRIMARY KEY, '
- . '[username] VARCHAR(50) UNIQUE NOT NULL, '
- . '[password] VARCHAR(32) NULL, '
- . '[real_name] VARCHAR(150) NULL)';
- // Tworzymy tabelę z danymi uwierzytelniania
- $dbAdapter->query($sqlCreate);
- // Budujemy zapytanie wstawiające wiersz, dla którego możemy przeprowadzić
- // próbę uwierzytelniania
- $sqlInsert = "INSERT INTO users (username, password, real_name) "
- . "VALUES ('my_username', 'my_password', 'My Real Name')";
- // Wstawiamy dane
- $dbAdapter->query($sqlInsert);
- ]]></programlisting>
- <para>
- Gdy połączenie do bazy danych oraz dane w tabeli są już
- dostępne, możesz utworzyć instancję klasy
- <classname>Zend_Auth_Adapter_DbTable</classname>. Opcje konfiguracyjne
- mogą być przekazane do konstruktora lub przekazane jako
- parametry do metod dostępowych już po utworzeniu instancji:
- </para>
- <programlisting language="php"><![CDATA[
- // Konfigurujemy instancję za pomocą parametrów konstruktora
- $authAdapter = new Zend_Auth_Adapter_DbTable(
- $dbAdapter,
- 'users',
- 'username',
- 'password'
- );
- // ...lub konfigurujemy instancję za pomocą metod dostępowych
- $authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);
- $authAdapter
- ->setTableName('users')
- ->setIdentityColumn('username')
- ->setCredentialColumn('password')
- ;
- ]]></programlisting>
- <para>
- W tym momencie intancja adaptera uwierzytelniania jest gotowa
- do przeprowadzenia zapytań uwierzytelniających. W celu
- utworzenia zapytania, wejściowe dane uwierzytelniania
- są przekazywane do adaptera przed wywołaniem metody
- <methodname>authenticate()</methodname>:
- </para>
- <programlisting language="php"><![CDATA[
- // Ustawiamy wartości danych uwierzytelniania (np., z formularza logowania)
- $authAdapter
- ->setIdentity('my_username')
- ->setCredential('my_password');
- // Przeprowadzamy zapytanie uwierzytelniające, zapisując rezultat
- $result = $authAdapter->authenticate();
- ]]></programlisting>
- <para>
- Oprócz możliwości użycia metody <methodname>getIdentity()</methodname>
- obiektu rezultatu uwierzytelniania, obiekt
- <classname>Zend_Auth_Adapter_DbTable</classname> pozwala także na
- odebranie wiersza tabeli po udanym uwierzytelnieniu.
- </para>
- <programlisting language="php"><![CDATA[
- // Wyświetlamy tożsamość
- echo $result->getIdentity() . "\n\n";
- // Wyświetlamy wiersz rezultatów
- print_r($authAdapter->getResultRowObject());
- /* Wyświetlone dane:
- my_username
- Array
- (
- [id] => 1
- [username] => my_username
- [password] => my_password
- [real_name] => My Real Name
- )
- */
- ]]></programlisting>
- <para>
- Z tego względu, że wiersz tabeli zawiera dane potrzebne do
- uwierzytelniania, ważne jest, aby dane były zabezpieczone przed
- dostępem przez osoby nieuprawnione.
- </para>
- </example>
- </sect2>
- <sect2 id="zend.auth.adapter.dbtable.advanced.storing_result_row">
- <title>Zaawansowane użycie: Stałe przechowywanie obiektu DbTable Result</title>
- <para>
- Domyślnie <classname>Zend_Auth_Adapter_DbTable</classname> po udanym
- uwierzytelnieniu zwraca do obiektu uwierzytelniającego spowrotem
- tę samą tożsamość. W innym przykładzie użycia programista może
- chcieć przechować w stałym mechanizmie przechowywania
- <classname>Zend_Auth</classname> obiekt tożsamości zawierający inne użyteczne
- informacje. W takim przypadku może użyć metody
- <methodname>getResultRowObject()</methodname> aby zwrócić obiekt klasy
- <classname>stdClass</classname>. Poniższy kod ilustruje sposób jego użycia:
- </para>
- <programlisting language="php"><![CDATA[
- // uwierzytelniamy za pomocą Zend_Auth_Adapter_DbTable
- $result = $this->_auth->authenticate($adapter);
- if ($result->isValid()) {
- // przechowujemy tożsamość jako obiekt, w którym zwracane są jedynie
- // pola username oraz real_name
- $storage = $this->_auth->getStorage();
- $storage->write($adapter->getResultRowObject(array(
- 'username',
- 'real_name'
- )));
- // przechowujemy tożsamość jako obiekt, w którym kolumna zawierająca
- // hasło została pominięta
- $storage->write($adapter->getResultRowObject(
- null,
- 'password'
- ));
- /* ... */
- } else {
- /* ... */
- }
- ]]></programlisting>
- </sect2>
- <sect2 id="zend.auth.adapter.dbtable.advanced.advanced_usage">
- <title>Przykład zaawansowanego użycia</title>
- <para>
- O ile głównym przeznaczeniem komponentu <classname>Zend_Auth</classname>
- (i odpowiednio <classname>Zend_Auth_Adapter_DbTable</classname>) jest
- <emphasis>uwierzytelnianie</emphasis> a nie <emphasis>autoryzacja</emphasis>,
- jest kilka problemów które możemy rozwiązać odrobinę przekraczając
- pole zastosowań komponentu. Zależnie od tego jak zdecydujesz
- wyjaśnić swój problem, czasem może być przydatne rozwiązanie
- problemu autoryzacji podczas uwierzytelniania.
- </para>
- <para>
- Komponent <classname>Zend_Auth_Adapter_DbTable</classname> posiada
- pewien wbudowany mechanizm, który może być użyty do dodania dodatkowych
- warunków podczas uwierzytelniania, dzięki czemu można rozwiązać niektóre
- problemy.
- </para>
- <programlisting language="php"><![CDATA[
- // Wartość pola "status" dla tego konta nie jest równa wartości "compromised"
- $adapter = new Zend_Auth_Adapter_DbTable(
- $db,
- 'users',
- 'username',
- 'password',
- 'MD5(?) AND status != "compromised"'
- );
- // Wartość pola "active" dla tego konta jest równa wartości "TRUE"
- $adapter = new Zend_Auth_Adapter_DbTable(
- $db,
- 'users',
- 'username',
- 'password',
- 'MD5(?) AND active = "TRUE"'
- );
- ]]></programlisting>
- <para>
- Innym przykładem może być implementacja mechanizmu saltingu. Jest to
- technika pozwalająca w znaczny sposób zwiększyć bezpieczeństwo
- aplikacji. Polega ona na tym, że dołączając do każdego hasła losowy
- łańcuch znaków spowodujemy, że niemożliwe będzie przeprowadzenie
- ataku brute force na bazę danych w oparciu o przygotowany słownik.
- </para>
- <para>
- Zaczniemy od zmodyfikowania schematu tabeli bazy danych, aby móc
- przechowywać nasz łańcuch znaków salt:
- </para>
- <programlisting language="php"><![CDATA[
- $sqlAlter = "ALTER TABLE [users] "
- . "ADD COLUMN [password_salt] "
- . "AFTER [password]";
- $dbAdapter->query($sqlAlter);
- ]]></programlisting>
- <para>
- W prosty sposób wygenerujmy salt dla każdego rejestrującego się
- użytkownika:
- </para>
- <programlisting language="php"><![CDATA[
- for ($i = 0; $i < 50; $i++)
- {
- $dynamicSalt .= chr(rand(33, 126));
- }
- ]]></programlisting>
- <para>
- I skonfigurujmy sterownik bazy danych:
- </para>
- <programlisting language="php"><![CDATA[
- $adapter = new Zend_Auth_Adapter_DbTable(
- $db,
- 'users',
- 'username',
- 'password',
- "MD5(CONCAT('"
- . Zend_Registry::get('staticSalt')
- . "', ?, password_salt))"
- );
- ]]></programlisting>
- <note>
- <para>
- Możesz jeszcze zwiększyć bezpieczeństwo używając dodatkowo
- statycznego fragmentu łańcucha znaków umieszczonego na stałe
- w kodzie aplikacji. W przypadku, gdy atakujący uzyska dostęp
- do bazy danych (np. za pomocą ataku <acronym>SQL</acronym>
- injection), a nie będzie miał dostępu do kodu źródłowego,
- hasła wciąż będą dla niego nieprzydatne.
- </para>
- </note>
- <para>
- Innym sposobem jest użycie metody <methodname>getDbSelect()</methodname>
- klasy <classname>Zend_Auth_Adapter_DbTable</classname> po utworzeniu
- adaptera. Ta metoda zwróci obiekt klasy <classname>Zend_Db_Select</classname>,
- który ma być użyty do przeprowadzenia uwierzytalniania. Ważne jest, że
- ta metoda zawsze zwróci ten sam obiekt, niezależnie od tego czy metoda
- <methodname>authenticate()</methodname> została wywołana czy nie.
- Ten obiekt <emphasis>nie będzie</emphasis> posiadał żadnych informacji
- dotyczących nazwy tożsamości i hasła, ponieważ te dane będą umieszczone
- tam dopiero w czasie wywołania metody <methodname>authenticate()</methodname>.
- </para>
- <para>
- Przykładem sytuacji w której można by użyć metody getDbSelect()
- może być potrzeba sprawdzenia statusu użytkownika, czyli sprawdzenia
- czy konto użytkownika jest aktywne.
- </para>
- <programlisting language="php"><![CDATA[
- // Kontynuując poprzedni przykład
- $adapter = new Zend_Auth_Adapter_DbTable(
- $db,
- 'users',
- 'username',
- 'password',
- 'MD5(?)'
- );
- // pobieramy obiekt Zend_Db_Select (przez referencję)
- $select = $adapter->getDbSelect();
- $select->where('active = "TRUE"');
- // uwierytelniamy, z warunkiem users.active = TRUE
- $adapter->authenticate();
- ]]></programlisting>
- </sect2>
- </sect1>
|