Rozdział 3. Zend_Auth

Spis treści

3.1. Wprowadzenie
3.1.1. Adaptery
3.1.2. Resultat
3.1.3. Trwałość uwierzytelnionej tożsamości
3.1.4. Użycie Zend_Auth
3.2. Uwierzytelnianie w oparciu o tabelę bazy danych
3.2.1. Wprowadzenie
3.2.2. Zaawansowane użycie: Stałe przechowywanie obiektu DbTable Result
3.3. Uwierzytelnianie Digest
3.3.1. Wprowadzenie
3.3.2. Parametry
3.3.3. Tożsamość
3.4. HTTP Authentication Adapter
3.4.1. Introduction
3.4.2. Design Overview
3.4.3. Configuration Options
3.4.4. Resolvers
3.4.5. Basic Usage

3.1. Wprowadzenie

Zend_Auth zapewnia API do uwierzytelniania oraz zawiera konkretne adaptery uwierzytelniania dla najczęstszych przypadków użycia.

Komponent Zend_Auth jest związany tylko z uwierzytelnianiem, a nie z autoryzacją. Uwierzytelnianie luźno definiujemy jako określanie w oparciu o pewien zestaw danych tego, czy dana jednostka jest tym na co wygląda (np. identyfikacja). Autoryzacja, proces decydowania o tym, czy zezwolić danej jednostce na dostęp lub przeprowadzanie operacji na innych jednostkach, jest poza polem działania Zend_Auth. Aby uzyskać więcej informacji o autoryzacji i kontroli dostępu za pomocą Zend Framework, proszę zobacz Zend_Acl.

[Notatka] Notatka

Klasa Zend_Auth implementuje wzorzec singletona, czyli dostępna jest tylko jej jedna instancja - za pomocą statycznej metody getInstance(). Oznacza to, że użycie operatorów new oraz clone nie będzie możliwe z klasą Zend_Auth; zamiast nich użyj metody Zend_Auth::getInstance().

3.1.1. Adaptery

Adapter Zend_Auth jest używany do uwierzytelniania na podstawie serwisu konkretnego typu, takiego jak LDAP, RDBMS, lub system plików. Różne adaptery mogą mieć różne opcje i mogą inaczej się zachowywać, ale niektóre podstawowe funkcjonalności są wspólne dla wszystkich adapterów. Na przykład akceptowanie danych uwierzytelniania, przeprowadzanie zapytań do serwisu uwierzytelniania i zwracanie rezultatów są wspólne dla adapterów Zend_Auth.

Każda klasa adaptera Zend_Auth implementuje interfejs Zend_Auth_Adapter_Interface. Ten interfejs definiuje jedną metodę, authenticate(), którą klasa adaptera musi implementować dla zastosowań przeprowadzania zapytania uwierzytelniania. Każda klasa adaptera musi być przygotowana przed wywołaniem metody authenticate(). Przygotowanie takiego adaptera obejmuje ustawienie danych uwierzytelniania (np. nazwy użytkownika i hasła) oraz zdefiniowanie wartości dla specyficznych opcji adaptera, na przykład ustawienie połączenia do bazy danych dla adaptera tabeli bazy danych.

Poniżej jest przykładowy adapter uwierzytelniania, który do przeprowadzenia procesu wymaga ustawionej nazwy użytkownika oraz hasła. Inne szczegóły, takie jak sposób przeprowadzania zapytania uwierzytelniającego, zostały pominięte w celu zwiększenia czytelności:

<?php
require_once 'Zend/Auth/Adapter/Interface.php';

class MyAuthAdapter implements Zend_Auth_Adapter_Interface
{
    /**
     * Ustawia nazwę użytkownika oraz hasła dla uwierzytelniania
     *
     * @return void
     */
    public function __construct($username, $password)
    {
        // ...
    }

    /**
     * Przeprowadza próbę uwierzytelniania
     *
     * @throws Zend_Auth_Adapter_Exception Jeśli uwierzytelnianie nie może być przeprowadzone
     * @return Zend_Auth_Result
     */
    public function authenticate()
    {
        // ...
    }
}

Jak pokazano w bloku dokumentacyjnym , metoda authenticate() musi zwracać instancję Zend_Auth_Result (lub instancję klasy rozszerzającej Zend_Auth_Result). Jeśli z jakiegoś powodu przeprowadzenie zapytania uwierzytelniającego jest niemożliwe, metoda authenticate() powinna wyrzucić wyjątek rozszerzający Zend_Auth_Adapter_Exception.

3.1.2. Resultat

Adaptery Zend_Auth zwracają instancję Zend_Auth_Result za pomocą metody authenticate() w celu przekazania rezultatu próby uwierzytelniania. Adaptery wypełniają obiekt Zend_Auth_Result podczas konstrukcji, dlatego poniższe trzy metody zapewniają podstawowy zestaw operacji, które są wspólne dla rezultatów adapterów Zend_Auth:

  • isValid() - zwraca logiczną wartość true tylko wtedy, gdy rezultat reprezentuje udaną próbę uwierzytelniania.

  • getCode() - returns a Zend_Auth_Result constant identifier for determining the type of authentication failure or whether success has occurred. This may be used in situations where the developer wishes to distinguish among several authentication result types. This allows developers to maintain detailed authentication result statistics, for example. Another use of this feature is to provide specific, customized messages to users for usability reasons, though developers are encouraged to consider the risks of providing such detailed reasons to users, instead of a general authentication failure message. For more information, see the notes below.

  • getIdentity() - zwraca tożsamość próby uwierzytelniania

  • getMessages() - zwraca tablicę wiadomości odnoszących się do nieudanej próby uwierzytelniania

A developer may wish to branch based on the type of authentication result in order to perform more specific operations. Some operations developers might find useful are locking accounts after too many unsuccessful password attempts, flagging an IP address after too many nonexistent identities are attempted, and providing specific, customized authentication result messages to the user. The following result codes are available:

Zend_Auth_Result::SUCCESS
Zend_Auth_Result::FAILURE
Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND
Zend_Auth_Result::FAILURE_IDENTITY_AMBIGUOUS
Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID
Zend_Auth_Result::FAILURE_UNCATEGORIZED

The following example illustrates how a developer may branch on the result code:

<?php
// wewnątrz akcji loginAction kontrolera AuthController
$result = $this->_auth->authenticate($adapter);

switch ($result->getCode()) {

    case Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND:
        /** do stuff for nonexistent identity **/
        break;

    case Zend_Auth_Result::FAILURE_INVALID_CREDENTIAL:
        /** do stuff for invalid credential **/
        break;

    case Zend_Auth_Result::SUCCESS:
        /** do stuff for successful authentication **/
        break;

    default:
        /** do stuff for other failure **/
        break;
}

3.1.3. Trwałość uwierzytelnionej tożsamości

Uwierzytelnianie żądania, które zawiera dane uwierzytelniające jest samo w sobie użyteczne, ale ważna jest także obsługa uwierzytelnionej tożsamości bez konieczności dołączania danych uwierzytelniających do każdego żądania.

HTTP jest protokołem niezachowującym stanu pomiędzy żądaniami, a techniki takie jak pliki cookie oraz sesje zostały stworzone w celu ułatwienia zarządzania stanem pomiędzy żądaniami w aplikacjach serwerowych.

3.1.3.1. Domyślne przechowywanie w sesji PHP

By default, Zend_Auth provides persistent storage of the identity from a successful authentication attempt using the PHP session. Upon a successful authentication attempt, Zend_Auth::authenticate() stores the identity from the authentication result into persistent storage. Unless configured otherwise, Zend_Auth uses a storage class named Zend_Auth_Storage_Session, which, in turn, uses Zend_Session. A custom class may instead be used by providing an object that implements Zend_Auth_Storage_Interface to Zend_Auth::setStorage().

[Notatka] Notatka

If automatic persistent storage of the identity is not appropriate for a particular use case, then developers may forgo using the Zend_Auth class altogether, instead using an adapter class directly.

Przykład 3.1. Modyfikowanie przestrzeni nazw sesji

Zend_Auth_Storage_Session używa przestrzeni nazw sesji o nazwie 'Zend_Auth'. This namespace may be overridden by passing a different value to the constructor of Zend_Auth_Storage_Session, and this value is internally passed along to the constructor of Zend_Session_Namespace. This should occur before authentication is attempted, since Zend_Auth::authenticate() performs the automatic storage of the identity.

<?php
// Zapisujemy referencję do pojedynczej instancji Zend_Auth
require_once 'Zend/Auth.php';
$auth = Zend_Auth::getInstance();

// Używamy przestrzeni nazw 'someNamespace' zamiast 'Zend_Auth'
require_once 'Zend/Auth/Storage/Session.php';
$auth->setStorage(new Zend_Auth_Storage_Session('someNamespace'));

/**
 * @todo Ustawić adapter uwierzytelniania, $authAdapter
 */

// Uwierzytelniamy, zapisując wynik i przechowując tożsamość po udanym uwierzytelnieniu
$result = $auth->authenticate($authAdapter);

3.1.3.2. Implementacja własnego pojemnika

Sometimes developers may need to use different identity persistence behavior than that provided by Zend_Auth_Storage_Session. For such cases developers may simply implement Zend_Auth_Storage_Interface and supply an instance of the class to Zend_Auth::setStorage().

Przykład 3.2. Użycie własnej klasy do przechowywania tożsamości

In order to use a identity persistence storage class other than Zend_Auth_Storage_Session, a developer implements Zend_Auth_Storage_Interface:

<?php
require_once 'Zend/Auth/Storage/Interface.php';

class MyStorage implements Zend_Auth_Storage_Interface
{
    /**
     * Zwraca wartość logiczną true tylko wtedy gdy pojemnik jest pusty
     *
     * @throws Zend_Auth_Storage_Exception If it is impossible to determine whether storage is empty
     * @return boolean
     */
    public function isEmpty()
    {
        /**
         * @todo implementacja
         */
    }

    /**
     * Zwraca zawartość pojemnika
     *
     * Behavior is undefined when storage is empty.
     *
     * @throws Zend_Auth_Storage_Exception If reading contents from storage is impossible
     * @return mixed
     */
    public function read()
    {
        /**
         * @todo implementacja
         */
    }

    /**
     * Zapisuje zawartość $contents w pojemniku
     *
     * @param  mixed $contents
     * @throws Zend_Auth_Storage_Exception If writing $contents to storage is impossible
     * @return void
     */
    public function write($contents)
    {
        /**
         * @todo implementacja
         */
    }

    /**
     * Czyści zawartość pojemnika
     *
     * @throws Zend_Auth_Storage_Exception If clearing contents from storage is impossible
     * @return void
     */
    public function clear()
    {
        /**
         * @todo implementacja
         */
    }

}

W celu użycia własnej klasy pojemnika, wywołaj metodę Zend_Auth::setStorage() przed przeprowadzeniem zapytania uwierzytelniającego:

<?php
// Instruct Zend_Auth to use the custom storage class
Zend_Auth::getInstance()->setStorage(new MyStorage());

/**
 * @todo Ustawić adapter uwierzytelniania, $authAdapter
 */

// Uwierzytelniamy, zapisując wynik i przechowując tożsamość po udanym uwierzytelnieniu
$result = Zend_Auth::getInstance()->authenticate($authAdapter);

3.1.4. Użycie Zend_Auth

Są dwa możliwe sposoby użycia adapterów Zend_Auth:

  1. pośrednio, za pomocą metody Zend_Auth::authenticate()

  2. bezpośrednio, za pomocą metody authenticate() adaptera

Poniższy przykład pokazuje jak użyć adaptera Zend_Auth pośrednio, poprzez użycie klasy Zend_Auth:

<?php
// Pobieramy instancję Zend_Auth
require_once 'Zend/Auth.php';
$auth = Zend_Auth::getInstance();

// Ustawiamy adapter uwierzytelniania
$authAdapter = new MyAuthAdapter($username, $password);

// Przeprowadzamy uwierzytelnianie, zapisując rezultat
$result = $auth->authenticate($authAdapter);

if (!$result->isValid()) {
    // Uwierzytelnianie nieudane; wyświetlamy powody
    foreach ($result->getMessages() as $message) {
        echo "$message\n";
    }
} else {
    // Uwierzytelnianie udane; tożsamość ($username) jest zapisana w sesji
    // $result->getIdentity() === $auth->getIdentity()
    // $result->getIdentity() === $username
}

Jeśli uwierzytelnianie zostało przeprowadzone w żądaniu tak jak w powyższym przykładzie, prostą sprawą jest sprawdzenie czy istnieje pomyślnie uwierzytelniona tożsamość:

<?php
$auth = Zend_Auth::getInstance();
if ($auth->hasIdentity()) {
    // Tożsamość istnieje; pobieramy ją
    $identity = $auth->getIdentity();
}

Aby usunąć tożsamość z trwałego pojemnika, użyj po prostu metody clearIdentity(). Typowo może być to użyte do implementacji w aplikacji operacji wylogowania:

<?php
Zend_Auth::getInstance()->clearIdentity();

Gdy automatyczne użycie trwałego pojemnika jest nieodpowiednie w konkretnym przypadku, programista może w prostu sposób ominąć użycie klasy Zend_Auth, używając bezpośrednio klasy adaptera. Bezpośrednie użycie klasy adaptera powoduje skonfigurowanie i przygotowanie obiektu adaptera, a następnie wywołanie metody authenticate(). Szczegóły specyficzne dla adaptera są opisane w dokumentacji dla każdego z adapterów. Poniższy przykład bezpośrednio używa MyAuthAdapter:

<?php
// Ustawiamy adapter uwierzytelniania
$authAdapter = new MyAuthAdapter($username, $password);

// Przeprowadzamy uwierzytelnianie, zapisując rezultat
$result = $authAdapter->authenticate();

if (!$result->isValid()) {
    // Uwierzytelnianie nieudane; wyświetlamy powody
    foreach ($result->getMessages() as $message) {
        echo "$message\n";
    }
} else {
    // Uwierzytelnianie udane
    // $result->getIdentity() === $username
}