|
|
@@ -0,0 +1,470 @@
|
|
|
+<?xml version="1.0" encoding="UTF-8"?>
|
|
|
+<!-- 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:
|
|
|
+-->
|