<?xml version="1.0" encoding="UTF-8"?>
<!-- EN-Revision: 24249 -->
<!-- Reviewed: no -->
<sect1 id="zend.auth.introduction">
    <title>Введение</title>

    <para>
        <classname>Zend_Auth</classname> предоставляет <acronym>API</acronym> для аутентификации и
        включает в себя конкретные адаптеры для общих случаев применения.
    </para>

    <para>
        Задачей <classname>Zend_Auth</classname> является <emphasis>аутентификация</emphasis>,
        но не <emphasis>авторизация</emphasis>. Аутентификацию в общих чертах можно характеризовать
        как процесс определения, действительно ли сущность является тем, чем она претендует быть
        (то есть идентификация), на основании некоторого набора учетных данных. Авторизация же -
        процесс определения того, можно ли предоставить сущности доступ или разрешить выполнить
        действие, и это полностью вне сферы компетенции <classname>Zend_Auth</classname>.
        Дополнительную информацию об авторизации и контроле доступа в Zend Framework смотрите в 
        <link linkend="zend.acl"><classname>Zend_Acl</classname></link>.
    </para>

    <note>
        <para>
            Класс <classname>Zend_Auth</classname> реализует паттерн Синглтон - только один экзмепляр
             класса доступен – через статический метод <methodname>getInstance()</methodname>. Это
             означает, что ключевые слова <emphasis>new</emphasis> или <emphasis>clone</emphasis> не
             будут работать с классом <classname>Zend_Auth</classname>. Вместо них используйте
             <methodname>Zend_Auth::getInstance()</methodname>.
        </para>
    </note>

    <sect2 id="zend.auth.introduction.adapters">
        <title>Адаптеры</title>

        <para>
            Адаптер <classname>Zend_Auth</classname> используется дла аутентификации посредством
            определенного сервиса, такого как <acronym>LDAP</acronym>, <acronym>СУРБД</acronym> или
            файлового хранилища. Адаптеры могут значительно различаться, но некоторые основные черты
            характерны для всех. Например, все адаптеры <classname>Zend_Auth</classname> принимают
            учетные данные, выполненяют запрос к аутентификационному сервису и возвращают результат. 
           
        </para>
        <para>
            Каждый адаптер <classname>Zend_Auth</classname> реализует 
            <classname>Zend_Auth_Adapter_Interface</classname>. Этот интерфейс определяет лишь один
            метод: <methodname>authenticate()</methodname>, который должен быть реализовать для
            выполнения аутентификационного запроса. Адаптер должен быть настроен до вызова
            <methodname>authenticate()</methodname>, настройка включает в себя установку учетных
            данных(например, логин и пароль) и определение специфичных значений, таких как настройки
            подключения к базе данных для адаптера таблиц БД.
        </para>

        <para>
            Это пример адаптера, требующего установки логина и пароля для аутентификации. Прочие
            детали, например каким образом аутентификационный сервис запрашивается, были опущены для
            кратости:
        </para>

        <programlisting language="php"><![CDATA[
class MyAuthAdapter implements Zend_Auth_Adapter_Interface
{
    /**
     * Устанавливает логин и пароль для аутентификации
     *
     * @return void
     */
    public function __construct($username, $password)
    {
        // ...
    }

    /**
     * Выполняет попытку аутентификации
     *
     * @throws Zend_Auth_Adapter_Exception Если аутентификация не может быть выполнена
     * @return Zend_Auth_Result
     */
    public function authenticate()
    {
        // ...
    }
}
]]></programlisting>

        <para>
            Как указано в докблоке, <methodname>authenticate()</methodname> должен вернуть экземпляр
            <classname>Zend_Auth_Result</classname> (или унаследованный от него). Если по какой либо
            причине выполнение аутентификации невозможно, <methodname>authenticate()</methodname>
            должен бросить исключение, происходящее от
            <classname>Zend_Auth_Adapter_Exception</classname>.
        </para>
    </sect2>

    <sect2 id="zend.auth.introduction.results">
        <title>Результат аутентификации</title>

        <para>
            Метод <methodname>authenticate()</methodname> адаптера <classname>Zend_Auth</classname>
            возвращает экзмепляр <classname>Zend_Auth_Result</classname> для представления 
            результата попытки аутентификации. Объект <classname>Zend_Auth_Result</classname>
            заполняется адаптером при создании, и следующие четыре метода представляют его базовый
            набор операций:
        </para>

        <itemizedlist>
            <listitem>
                <para>
                    <methodname>isValid()</methodname> - возвращает <constant>TRUE</constant> только
                    в случае успешной попытки аутентификации.
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>getCode()</methodname> - возвращает значение одной из констант
                    <classname>Zend_Auth_Result</classname> для обозначения успешности попытки или
                    типа возникшей ошибки. Это может быть использовано в ситуации, когда разработчик
                    хочет различать результаты попыток аутентификации. К примеру, он может вести
                    детальную статистку всех попыток, либо выводить нестандартные сообщения для
                    удобства пользователей. Но при этом стоит учитывать риски предоставления
                    пользователям подробных сведений вместо стандартных сообщений о неудаче.
                    Подробнее о возвращаемых значениях смотрите ниже.
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>getIdentity()</methodname> - возвращает идентификатор, полученный в
                    результе аутентификации.
                </para>
            </listitem>

            <listitem>
                <para>
                    <methodname>getMessages()</methodname> - возвращает массив сообщений о ошибках,
                    возникших в процессе попытки аутентификации.
                </para>
            </listitem>
        </itemizedlist>

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

        <programlisting language="php"><![CDATA[
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
]]></programlisting>

        <para>
            Этот пример показывает, как разработчик может различным образом обработать результат
            аутентификации, используя значение кода:
        </para>

        <programlisting language="php"><![CDATA[
// в AuthController / loginAction
$result = $this->_auth->authenticate($adapter);

switch ($result->getCode()) {

    case Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND:
        /** Выполнить действия при несуществующем идентификаторе **/
        break;

    case Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID:
        /** Выполнить действия при некорректных учетных данных **/
        break;

    case Zend_Auth_Result::SUCCESS:
        /** Выполнить действия при успешной аутентификации **/
        break;

    default:
        /** Выполнить действия для остальных ошибок **/
        break;
}
]]></programlisting>
    </sect2>

    <sect2 id="zend.auth.introduction.persistence">
        <title>Постоянное хранение идентификатора пользователя</title>

        <para>
            Аутентификация запроса, содержащего учетные данные, важна сама по себе, но также важно
            поддерживать сохранение идентификатора без необходимости передачи учетных данных с
            каждым запросом.
        </para>

        <para>
            Протокол <acronym>HTTP</acronym> не имеет состояний, однако были разработаны такие
            технологии как куки(cookies) и сессии для поддержки состояния на стороне сервера между
            несколькими запросами к веб приложению.
        </para>

        <sect3 id="zend.auth.introduction.persistence.default">
            <title>Сохранение идентификатора в сессии PHP, по умолчанию</title>

            <para>
                 По умолчанию, <classname>Zend_Auth</classname> обеспечивает постоянное хранение
                 идентификатора полученного в результате успешной попытки аутентификации в
                 <acronym>PHP</acronym> сессии.
            </para>
            <para>
                При успешной попытке, <methodname>Zend_Auth::authenticate()</methodname> сохраняет
                идентификатор в постоянном хранилище. Если не настроено по другому,
                <classname>Zend_Auth</classname> использует класс хранилища
                <classname>Zend_Auth_Storage_Session</classname>, который в свою очередь использует
                <link linkend="zend.session"><classname>Zend_Session</classname></link>.
                Вместо него может быть использован пользовательский класс, для этого нужно 
                передать <methodname>Zend_Auth::setStorage()</methodname> объект, реализующий
                <classname>Zend_Auth_Storage_Interface</classname>.
            </para>

            <note>
                <para>
                    Если автоматическое сохранение идентификатора не подходит в каком-либо
                    конкретном случае, тогда разработчику следует отказаться от использования класса
                    <classname>Zend_Auth</classname> и использовать адаптер напрямую.
                </para>
            </note>

            <example id="zend.auth.introduction.persistence.default.example">
                <title>Изменение пространства имен в сессии</title>

                <para>
                    <classname>Zend_Auth_Storage_Session</classname> использует пространство имен
                    '<classname>Zend_Auth</classname>'. Оно может быть переопределено передачей
                    другого значения конструктору <classname>Zend_Auth_Storage_Session</classname>,
                    которое будет дальше передано конструктору 
                    <classname>Zend_Session_Namespace</classname>. Это нужно сделать до того, как
                    будет произведена попытка аутентификации, так как
                    <methodname>Zend_Auth::authenticate()</methodname> выполняет автоматическое
                    сохранение идентификатора.
                </para>

                <programlisting language="php"><![CDATA[
// Получение синглтон экземпляра Zend_Auth
$auth = Zend_Auth::getInstance();

// Установка 'someNamespace' вместо 'Zend_Auth'
$auth->setStorage(new Zend_Auth_Storage_Session('someNamespace'));

/**
 * @todo подготовка адаптера, $authAdapter
 */

// Аутентификация, сохранение результата, и хранение идентификатора
// при успехе.
$result = $auth->authenticate($authAdapter);
]]></programlisting>
            </example>
        </sect3>

        <sect3 id="zend.auth.introduction.persistence.custom">
            <title>Реализация пользовательского хранилища</title>

            <para>
                Иногда разработчику может понадобиться использовать иной механизм хранения
                идентификаторов, нежели предоставляется в
                <classname>Zend_Auth_Storage_Session</classname>. В том случае он может реализовать
                <classname>Zend_Auth_Storage_Interface</classname> и передать экземпляр
                методу <methodname>Zend_Auth::setStorage()</methodname>.
            </para>

            <example id="zend.auth.introduction.persistence.custom.example">
                <title>Использование пользовательского хранилища</title>

                <para>
                    Для того, чтобы использовать иной класс хранилища пользовательских
                    идентификаторов, нежели <classname>Zend_Auth_Storage_Session</classname>,
                    разработчик реализует <classname>Zend_Auth_Storage_Interface</classname>:
                </para>

                <programlisting language="php"><![CDATA[
class MyStorage implements Zend_Auth_Storage_Interface
{
    /**
     * Возвращает  true, если хранилище пусто
     *
     * @throws Zend_Auth_Storage_Exception В случае если невозможно
     *                                     определить, пусто ли
     *                                     хранилище
     * @return boolean
     */
    public function isEmpty()
    {
        /**
         * @todo реализация
         */
    }

    /**
     * Возвращает содержимое хранилища
     *
     * Поведение неопределено, когда хранилище пусто.
     *
     * @throws Zend_Auth_Storage_Exception Если получение содержимого
     *                                     хранилища невозможно
     * @return mixed
     */
    public function read()
    {
        /**
         * @todo реализация
         */
    }

    /**
     * Записывает $contents в хранилище
     *
     * @param  mixed $contents
     * @throws Zend_Auth_Storage_Exception Если запись содержимого в
     *                                     хранилище невозможна
     * @return void
     */
    public function write($contents)
    {
        /**
         * @todo реализация
         */
    }

    /**
     * Очищает содержмое хранилища
     *
     * @throws Zend_Auth_Storage_Exception Если очищение хранилища
     *                                     невозможно
     * @return void
     */
    public function clear()
    {
        /**
         * @todo реализация
         */
    }
}
]]></programlisting>

                <para>
                    Для использования этого класса, <methodname>Zend_Auth::setStorage()</methodname>
                    вызывается до выполнения попытки авторизации:
                </para>

                <programlisting language="php"><![CDATA[
// Сказать Zend_Auth использовать пользовательский класс хранилища
Zend_Auth::getInstance()->setStorage(new MyStorage());

/**
 * @todo подготовка адаптера, $authAdapter
 */

// Аутентификация, сохранение результата, и хранение идентификатора
// при успехе.
$result = Zend_Auth::getInstance()->authenticate($authAdapter);
]]></programlisting>
            </example>
        </sect3>
    </sect2>

    <sect2 id="zend.auth.introduction.using">
        <title>Использование</title>

        <para>
            Существует два пути использования адаптеров <classname>Zend_Auth</classname>:
        </para>

        <orderedlist>
            <listitem>
                <para>
                    непрямое, через <methodname>Zend_Auth::authenticate()</methodname>
                </para>
            </listitem>

            <listitem>
                <para>
                    прямое, через метод адаптера <methodname>authenticate()</methodname>
                </para>
            </listitem>
        </orderedlist>

        <para>
            Следующий пример показывает, как использовать адаптер <classname>Zend_Auth</classname>
            через класс <classname>Zend_Auth</classname>:
        </para>

        <programlisting language="php"><![CDATA[
// Получение синглтон экземпляра Zend_Auth
$auth = Zend_Auth::getInstance();

// Установка адаптера
$authAdapter = new MyAuthAdapter($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
}
]]></programlisting>

        <para>
            После того как попытка аутентификации была произведена, как показано в примере выше,
            теперь нужно только проверить, существует ли аутентифицированный идентификатор:
        </para>

        <programlisting language="php"><![CDATA[
$auth = Zend_Auth::getInstance();
if ($auth->hasIdentity()) {
    // Идентификатор существует; получить его
    $identity = $auth->getIdentity();
}
]]></programlisting>

        <para>
            Для удаления идентификатора из постоянного хранилища, просто используйте метод
            <methodname>clearIdentity()</methodname>. Обычно это используется для реализации
            действия "Выйти":
        </para>

        <programlisting language="php"><![CDATA[
Zend_Auth::getInstance()->clearIdentity();
]]></programlisting>

        <para>
            Когда автоматическое использование постоянного хранилища не подходит, разработчик
            может просто обойти <classname>Zend_Auth</classname> и использовать класс адаптера
            напрямую. Прямое использование адаптера включает в себя настройку, подготовку объекта
            адаптера и последующий вызов его метода, <methodname>authenticate()</methodname>.
            Специфичные для адаптера детали обсуждаются в документации этого адаптера. Следующий
            пример напрямую использует <classname>MyAuthAdapter</classname>:
        </para>

        <programlisting language="php"><![CDATA[
// Подготовка адаптера
$authAdapter = new MyAuthAdapter($username, $password);

// Попытка аутентификации, сохранение результата
$result = $authAdapter->authenticate();

if (!$result->isValid()) {
    // Попытка неуспешна; вывести сообщения об ошибках
    foreach ($result->getMessages() as $message) {
        echo "$message\n";
    }
} else {
    // Попытка успешна;
    // $result->getIdentity() === $username
}
]]></programlisting>
    </sect2>
</sect1>
<!--
vim:se ts=4 sw=4 et:
-->
