Содержание


Authentication (Аутентификация)


Authentication, ZF2, Zend Framawork 2




Компонент Zend\Authentication предоставляет API для аутентификации и содержит конкретные адаптеры аутентификации для наиболее распространенных сценариев
использования.

Zend\Authentication предназначен только для аутентификации, но не для авторизации. Аутентификацию в широком смысле можно определить, как процедуру распознавания того, действительно ли некто является тем, кем он претендует быть (т.е., идентификация), основанную на некотором наборе учетных данных. Авторизация, т.е. процесс принятия решения о том, следует ли разрешить определенному лицу доступ к некоторым сущностям или к выполнению операций над ними, лежит за рамками Zend\Authentication. Дополнительные сведения по авторизации и контролю доступа в Zend Framework см. в компоненте Zend\PermissionsAcl или ZendPermissionsRbac.

Примечание: Не существует класса Zend\Authentication\Authentication, вместо этого предоставляется класс Zend\Аuthentication\AuthenticationService. Этот класс использует основные адаптеры аутентификации и внутренние механизмы персистентности.

Адаптеры

Адаптеры Zend\Authentication используются для проверки подлинности на основе конкретного типа аутенификационных сервисов, таких, как LDAP, RDBMS, или сервисам на основе файловых хранилищ. У различныех адаптеров, насколько это можно ожидать, будут различные параметры и поведение, однако адаптеры аутентификации имеют и нечто общее. Например, прием учетных данных аутентификации (включая подразумеваемую идентичность), выполнение запросов к
сервису аутентификации и возвращение результатов, присуще всем адаптерам Zend\Authentication.

Каждый класс адаптера Zend\Authentication реализует интерфейс ZendAuthentication\Adapter\AdapterInterface. В этом интерфейсе определен единственный метод authenticate(), который каждый класс адаптера должен реализовать для выполнения запроса аутентификации. Каждый класс адаптера должен быть соответствующим образом подготовлен к вызову метода authenticate(). Такая подготовка адаптера включает в себя обеспечение учетными данными (например, именем пользователя и паролем) и установку значений, специфических для каждого адаптера, подобно параметрам соединения с базой данных для адаптера DbTable.

Ниже приведен пример пример адаптера аутентификации, для выполнения аутентификации которого требуется установить имя пользователя и пароль. Другие детали, такие, как сервис аутентификации, который будет запрашиваться, опущены для краткости.

use Zend\Authentication\Adapter\AdapterInterface;
 
class My\Auth\Adapter implements AdapterInterface
{
    /**
     * Устанавливает имя пользователя и пароль для
аутентификации
     *
     * @return void
     */
    public function __construct($username, $password)
    {
        // ...
    }
 
    /**
     * Пытается выполнить аутентификацию
     *
     * @return \Zend\Authentication\Result
     * @throws \Zend\Authentication\Adapter\Exception\ExceptionInterface
     *               Если не удастся выполнить аутентификацию
     */
    public function authenticate()
    {
        // ...
    }
}
 

Как указано в документируемых комментариях, метод
authenticate() должен вернуть экземпляр
Zend\Authentication\Result (или класс, производный от
Zend\Authentication\Result). Если по какой-либо причине
выполнение запроса аутентификации не возможно, метод
authenticate() должен бросить исключение, производное от
Zend\Authentication\Adapter\Exception\ExceptionInterface.

Результаты

Метод authenticate() адаптеров Zend\Authentication возвращает экземпляр Zend\Authentication\Result для предоставления результатов аутентификации. Адаптеры заполняют объект Zend\Authentication\Result при конструировании, и таким образом следующие четыре метода предоставляют базовый набор пользовательских операций, который является общим для результатов всех адаптеров Zend\Authentication:


isValid() - возвращает TRUE тогда, и только тогда, когда результат представляет собой успешную попытку аутентификации.
getCode() - возвращает идентификатор в виде константы Zend\Authentication\Result для определения успешной аутентификации или типа сбоя аутентификации. Это может быть использовано, когда разработчик желает найти отличия между различными типами результатов аутентификации. 

Например, это позволит разработчику вести подробную статистику результатов аутенификации. Другой способ использовать данную функциональность заключается в предоставлении пользователям характерных индивидуальных сообщений по соображениям удобства и простоты использования, хотя разработчикам рекомендуется рассмотреть риски предоставления пользователям такого подробного изложения причин вместо обобщенного сообщения об ошибке аутентификации.

  Дополнительную информацию смотрите в примечаниях ниже.
getIdentity() - возвращает идентификатор, полученный при попытке аутентификации.
getMessages() - возвращает массив сообщений о неудачной попытке аутентификации.

Разработчики могут пожелать расширить приложение более специфическими операциями в зависимости от типа результата аутентификации. Некоторые операции разработчики могут найти полезными, например, блокировка аккаунта после многочисленных неудачных попыток ввода пароля, маркировка IP адреса после многократного предоставления несуществующих идентификаторов и предоставление конкретных индивидуальных сообщений результатов аутентификации
пользователям.

Доступны следующие коды результата аутенификации:

use Zend\Authentication\Result;
 
Result::SUCCESS
Result::FAILURE
Result::FAILURE_IDENTITY_NOT_FOUND
Result::FAILURE_IDENTITY_AMBIGUOUS
Result::FAILURE_CREDENTIAL_INVALID
Result::FAILURE_UNCATEGORIZED
 
Следующий пример демонстрирует, как разработчик может использовать код результата аутентификации:

// в теле AuthController / loginAction
$result = $this->auth->authenticate($adapter);
 
switch ($result->getCode()) {
 
    case Result::FAILURE_IDENTITY_NOT_FOUND:
        /** выполнить при несуществующем идентификаторе
(например, логине) **/
        break;
 
    case Result::FAILURE_CREDENTIAL_INVALID:
        /** выполнить при недействительном наборе учетных
данных (например, пароле) **/
        break;
 
    case Result::SUCCESS:
        /** выполнить при успешной аутентификации **/
        break;
 
    default:
        /** выполнить при любой другой ошибке **/
        break;
}
 
Хранение признаков подлинности

Аутентификация запроса, который включает в себя учетные данные для аутентификации, полезна сама по себе, но важно также сохранять идентификатор подлинности (identity), который прошел проверку, чтобы не предоставлять учетные данные для аутенификации при каждом запросе.

HTTP является протоколом без сохранения состояния, однако такие методы, как cookies и сессии были разработаны, чтобы упростить поддержание состояния между несколькими запросами в серверных веб-приложениях.

Персистентность по умолчанию посредством PHP сессий

По умолчанию Zend\Authentication обеспечивает постоянное хранение идентификатора подлинности (identity) с помощью сессий php.  После успешной попытки аутентификации, Zend\Authentication\AuthenticationService::authenticate() сохраняет  идентификатор подлинности из результата идентификации в постоянном хранилище. Если не указано иное, Zend\Authentication\AuthenticationService использует в качестве класса хранилища Zend\Authentication\Storage\Session, который, в свою очередь, использует Zend\Session. Вместо этого может использоваться пользовательский класс путем предоставления объекта, реализующего интерфейс Zend\Authentication\Storage\StorageInterface, методу Zend\Аuthentication\AuthenticationService::setStorage().

Примечание:Если автоматическое постоянное хранилище идентификатора подлинности не подходит для какого-либо специфического случая, разработчики могут игнорировать использование класса ZendAuthenticationAuthenticationService и вместо этого использовать класс адаптера напрямую.

                                                                                                           Изменение пространства имен сессии

Zend\Authentication\Storage\Session использует в качестве пространства имен сессии ‘Zend_Auth‘. Это пространство имен может быть изменено путем передачи другого значения в конструктор Zend\Authentication\Storage\Session, и это значение автоматически будет передано конструктору Zend\Session\Container. Это должно произойти до попытки аутентификации, поскольку Zend\Authentication\AuthenticationService::authenticate() осуществляет автоматическое сохранение идентификатора подлинности.

use Zend\Authentication\AuthenticationService;
use Zend\Authentication\Storage\Session as SessionStorage;
 
$auth = new AuthenticationService();
 
// Использование 'someNamespace' вместо 'Zend_Auth'
$auth->setStorage(new SessionStorage('someNamespace'));
 
/**
 * @todo Установка адаптера аутентификации, $authAdapter
 */
 
// Аутентификация, получение результата и сохранения
идентификатора подлинности в случае успеха
$result = $auth->authenticate($authAdapter);
 
Цепочка хранилищ

Во-первых, сайт может использовать множество хранилищ. Цепочка хранилищ может быть использована для того, чтобы склеить их вместе.

Цепочка может, например, быть настроена на первоочередное использование Session Storage и последующее использование OAuth в качестве вторичного хранилища. Можно настроить это следующим образом:

$storage = new Chain;
$storage->add(new Session);
$storage->add(new OAuth); // Примечание: воображаемое хранилище, не является частью ZF2
 
Теперь, если цепочка хранилищ обратится к лежащим в ее основе хранилищам, она будет получать доступ к ним в том же порядке, в котором они были добавлены в цепочку. Таким образом, первым будет использовано хранилище Session Storage.
Теперь либо:
Session Storage не пусто, и цепочка будет использовать его содержимое
Session Storage пусто. Следующее обращение будет к хранилищу OAuth.
    • Если оно также пусто, цепочка хранилищ будет представлена, как пустая.
    • Если оно не пусто, цепочка будет использовать его содержимое. Однако она также заполнит все хранилища с более
высоким приоритетом. 
Таким образом, Session Storage будет заполнено содержимым хранилища OAuth.

Приоритет хранилищ в цепочке может быть задан с помощью
метода Chain::add
$chain->add(new A, 2);
$chain->add(new B, 10); // Первым используется B
 

Реализация пользовательских хранилищ

Иногда разработчикам может понадобиться другой механизм хранения идентичности, отличный от предоставляемого Zend\Authentication\Storage\Session. В таких случаях разработчики могут легко реализовать Zend\Authentication\Storage\StorageInterface и передать экземпляр этого класса в Zend\Authentication\AuthenticationService::setStorage().

Использование пользовательского класса хранилища

Для использования класса постоянного хранилища идентичности, отличного от Zend\Authentication\Storage\Session, разработчик реализовал класс Zend\Authentication\Storage\StorageInterface следующим образом:

use Zend\Authentication\Storage\StorageInterface;
 
class My\Storage implements StorageInterface
{
    /**
     * Вернет true тогда, и только тогда, когда хранилище пусто
     *
     * @throws \Zend\Authentication\Exception\ExceptionInterface
     *               Если невозможно определить, пусто ли хранилище
     * @return boolean
     */
    public function isEmpty()
    {
        /**
         * @todo реализация
         */
    }
 
    /**
     * Возвращает содержимое хранилища
     *
     * Поведение, в случае, если хранилище пусто, не определено.
     *
     * @throws \Zend\Authentication\Exception\ExceptionInterface
     *               Если чтение содержимого хранилища невозможно
     * @return mixed
     */
    public function read()
    {
        /**
         * @todo реализация
         */
    }
 
    /**
     * Записывает $contents в хранилище
     *
     * @param  mixed $contents
     * @throws \Zend\Authentication\Exception\ExceptionInterface
     *               Если запись в хранилище невозможна
     * @return void
     */
    public function write($contents)
    {
        /**
         * @todo реализация
         */
    }
 
    /**
     * Очистить содержимое хранилища
     *
     * @throws \Zend\Authentication\Exception\ExceptionInterface
     *               Если очистка содержимого хранилища невозможна
     * @return void
     */
 
    public function clear()
    {
        /**
         * @todo реализация
         */
    }
}

Для того, чтобы использовать этот пользовательский класс хранилища, Zend\Authentication\AuthenticationService::setStorage() вызывается до того, как производится попытка аутентификации:

use Zend\Authentication\AuthenticationService;
 
// Указать сервису AuthenticationService использовать
пользовательский класс хранилища
$auth = new AuthenticationService();
 
$auth->setStorage(new My\Storage());
 
/**
 * @todo Установка адаптера, $authAdapter
 */
 
// Аутентификация, получение результата и сохранение
идентичности в случае успеха
$result = $auth->authenticate($authAdapter);
 
Использование

Есть два предусмотренных способа использования адаптеров
Zend\Authentication: 
опосредованно, через Zend\Authentication\AuthenticationService::authenticate()
непосредственно, с помощью метода адаптера authenticate()

В следующем примере показано, как использовать Zend\Authentication адаптер косвенно, посредством класса ZendAuthenticationAuthenticationService:

use Zend\Authentication\AuthenticationService;
 
// экземпляр сервиса аутенификации
$auth = new AuthenticationService();
 
// Установка адаптера аутенификации
$authAdapter = new My\Auth\Adapter($username, $password);
 
// Попытка аутентификации, получение результата
$result = $auth->authenticate($authAdapter);
 
if (!$result->isValid()) {
    // Аутентификация не удалась, отображаем причины
    foreach ($result->getMessages() as $message) {
        echo "$message\n";
    }
} else {
    // Аутентификация успешна; сохраняем
    // идентичность ($username) в сессии
    // $result->getIdentity() === $auth->getIdentity()
    // $result->getIdentity() === $username
}
 
После того, как был сделан запрос на попытку аутентификации, как в приведенном выше примере, очень просто проверить, существует ли идентификатор подлинности успешной аутентификации:

use Zend\Authentication\AuthenticationService;
 
$auth = new AuthenticationService();
 
/**
 * @todo Установка адаптера, $authAdapter
 */
 
if ($auth->hasIdentity()) {
    // Идентификатор подлинности существует, получить его
    $identity = $auth->getIdentity();
}
 

Чтобы удалить идентификатор подлинности из постоянного хранилища, просто используйте метод clearIdentity(). Это, как правило, будет использоваться при реализации в приложении операции "logout".

$auth->clearIdentity();
Если автоматическое использование постоянного хранилища не подходит для конкретного случая, разработчик может просто не использовать класс Zend\Authentication\AuthenticationService, а использовать класс адаптера напрямую. Непосредственное использование класса адаптера включает в себя настройку и
подготовку объекта адаптера, а затем вызов его метода authenticate(). Детали, специфические для адаптера, обсуждаются в документации к каждому адаптеру. В следующем примере непосредственно используется адаптер My\Auth\Adapter:

// Установка адаптера аутенификации
$authAdapter = new My\Auth\Adapter($username, $password);
 
// Попытка аутенификации, получение результата
$result = $authAdapter->authenticate();
 
if (!$result->isValid()) {
    // Аутентификация не удалась, отображаем причины
    foreach ($result->getMessages() as $message) {
        echo "$message\n";
    }
} else {
    // Аутентификация успешна
    // $result->getIdentity() === $username
}