| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- Reviewed: no -->
- <sect1 id="zend.auth.introduction">
- <title>Introduction</title>
- <para>
- <classname>Zend_Auth</classname> provides an API for authentication and includes concrete authentication adapters for
- common use case scenarios.
- </para>
- <para>
- <classname>Zend_Auth</classname> is concerned only with <emphasis role="strong">authentication</emphasis> and not with
- <emphasis role="strong">authorization</emphasis>. Authentication is loosely defined as determining
- whether an entity actually is what it purports to be (i.e., identification), based on some set of
- credentials. Authorization, the process of deciding whether to allow an entity access to, or to
- perform operations upon, other entities is outside the scope of <classname>Zend_Auth</classname>. For more information about
- authorization and access control with Zend Framework, please see
- <link linkend="zend.acl"><classname>Zend_Acl</classname></link>.
- </para>
- <note>
- <para>
- The <classname>Zend_Auth</classname> class implements the Singleton pattern - only one instance of the class is
- available - through its static <code>getInstance()</code> method. This means that using the <code>new</code>
- operator and the <code>clone</code> keyword will not work with the <classname>Zend_Auth</classname> class; use
- <classname>Zend_Auth::getInstance()</classname> instead.
- </para>
- </note>
- <sect2 id="zend.auth.introduction.adapters">
- <title>Adapters</title>
- <para>
- A <classname>Zend_Auth</classname> adapter is used to authenticate against a particular type of authentication service,
- such as LDAP, RDBMS, or file-based storage. Different adapters are likely to have vastly different
- options and behaviors, but some basic things are common among authentication adapters. For example,
- accepting authentication credentials (including a purported identity), performing queries against the
- authentication service, and returning results are common to <classname>Zend_Auth</classname> adapters.
- </para>
- <para>
- Each <classname>Zend_Auth</classname> adapter class implements <classname>Zend_Auth_Adapter_Interface</classname>. This interface defines one
- method, <code>authenticate()</code>, that an adapter class must implement for performing an authentication
- query. Each adapter class must be prepared prior to calling <code>authenticate()</code>. Such adapter
- preparation includes setting up credentials (e.g., username and password) and defining values for adapter-
- specific configuration options, such as database connection settings for a database table adapter.
- </para>
- <para>
- The following is an example authentication adapter that requires a username and password to be set
- for authentication. Other details, such as how the authentication service is queried, have been
- omitted for brevity:
- <programlisting role="php"><![CDATA[
- class MyAuthAdapter implements Zend_Auth_Adapter_Interface
- {
- /**
- * Sets username and password for authentication
- *
- * @return void
- */
- public function __construct($username, $password)
- {
- // ...
- }
- /**
- * Performs an authentication attempt
- *
- * @throws Zend_Auth_Adapter_Exception If authentication cannot
- * be performed
- * @return Zend_Auth_Result
- */
- public function authenticate()
- {
- // ...
- }
- }
- ]]></programlisting>
- As indicated in its docblock, <code>authenticate()</code> must return an instance of
- <classname>Zend_Auth_Result</classname> (or of a class derived from <classname>Zend_Auth_Result</classname>). If for some
- reason performing an authentication query is impossible, <code>authenticate()</code> should throw
- an exception that derives from <classname>Zend_Auth_Adapter_Exception</classname>.
- </para>
- </sect2>
- <sect2 id="zend.auth.introduction.results">
- <title>Results</title>
- <para>
- <classname>Zend_Auth</classname> adapters return an instance of <classname>Zend_Auth_Result</classname> with
- <code>authenticate()</code> in order to represent the results of an authentication attempt. Adapters
- populate the <classname>Zend_Auth_Result</classname> object upon construction, so that the following four methods
- provide a basic set of user-facing operations that are common to the results of <classname>Zend_Auth</classname> adapters:
- <itemizedlist>
- <listitem>
- <para>
- <code>isValid()</code> - returns true if and only if the result represents a
- successful authentication attempt
- </para>
- </listitem>
- <listitem>
- <para>
- <code>getCode()</code> - returns a <classname>Zend_Auth_Result</classname> 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.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>getIdentity()</code> - returns the identity of the authentication attempt
- </para>
- </listitem>
- <listitem>
- <para>
- <code>getMessages()</code> - returns an array of messages regarding a failed
- authentication attempt
- </para>
- </listitem>
- </itemizedlist>
- </para>
- <para>
- 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:
- <programlisting role="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>
- The following example illustrates how a developer may branch on the result code:
- <programlisting role="php"><![CDATA[
- // inside of AuthController / loginAction
- $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_CREDENTIAL_INVALID:
- /** do stuff for invalid credential **/
- break;
- case Zend_Auth_Result::SUCCESS:
- /** do stuff for successful authentication **/
- break;
- default:
- /** do stuff for other failure **/
- break;
- }
- ]]></programlisting>
- </para>
- </sect2>
- <sect2 id="zend.auth.introduction.persistence">
- <title>Identity Persistence</title>
- <para>
- Authenticating a request that includes authentication credentials is useful per se, but it is also
- important to support maintaining the authenticated identity without having to present the
- authentication credentials with each request.
- </para>
- <para>
- HTTP is a stateless protocol, however, and techniques such as cookies and sessions have been
- developed in order to facilitate maintaining state across multiple requests in server-side web
- applications.
- </para>
- <sect3 id="zend.auth.introduction.persistence.default">
- <title>Default Persistence in the PHP Session</title>
- <para>
- By default, <classname>Zend_Auth</classname> provides persistent storage of the identity from a successful
- authentication attempt using the PHP session. Upon a successful authentication attempt,
- <classname>Zend_Auth::authenticate()</classname> stores the identity from the authentication result into
- persistent storage. Unless configured otherwise, <classname>Zend_Auth</classname> uses a storage class named
- <classname>Zend_Auth_Storage_Session</classname>, which, in turn, uses
- <link linkend="zend.session"><classname>Zend_Session</classname></link>. A custom class may instead be used by providing an
- object that implements <classname>Zend_Auth_Storage_Interface</classname> to
- <classname>Zend_Auth::setStorage()</classname>.
- </para>
- <note>
- <para>
- If automatic persistent storage of the identity is not appropriate for a particular use case, then
- developers may forgo using the <classname>Zend_Auth</classname> class altogether, instead using an adapter
- class directly.
- </para>
- </note>
- <example id="zend.auth.introduction.persistence.default.example">
- <title>Modifying the Session Namespace</title>
- <para>
- <classname>Zend_Auth_Storage_Session</classname> uses a session namespace of 'Zend_Auth'. This
- namespace may be overridden by passing a different value to the constructor of
- <classname>Zend_Auth_Storage_Session</classname>, and this value is internally passed along to the constructor
- of <classname>Zend_Session_Namespace</classname>. This should occur before authentication is attempted, since
- <classname>Zend_Auth::authenticate()</classname> performs the automatic storage of the identity.
- <programlisting role="php"><![CDATA[
- // Save a reference to the Singleton instance of Zend_Auth
- $auth = Zend_Auth::getInstance();
- // Use 'someNamespace' instead of 'Zend_Auth'
- $auth->setStorage(new Zend_Auth_Storage_Session('someNamespace'));
- /**
- * @todo Set up the auth adapter, $authAdapter
- */
- // Authenticate, saving the result, and persisting the identity on
- // success
- $result = $auth->authenticate($authAdapter);
- ]]></programlisting>
- </para>
- </example>
- </sect3>
- <sect3 id="zend.auth.introduction.persistence.custom">
- <title>Implementing Customized Storage</title>
- <para>
- Sometimes developers may need to use a different identity storage mechanism than that provided by
- <classname>Zend_Auth_Storage_Session</classname>. For such cases developers may simply implement
- <classname>Zend_Auth_Storage_Interface</classname> and supply an instance of the class to
- <classname>Zend_Auth::setStorage()</classname>.
- </para>
- <example id="zend.auth.introduction.persistence.custom.example">
- <title>Using a Custom Storage Class</title>
- <para>
- In order to use an identity persistence storage class other than
- <classname>Zend_Auth_Storage_Session</classname>, a developer implements
- <classname>Zend_Auth_Storage_Interface</classname>:
- <programlisting role="php"><![CDATA[
- class MyStorage implements Zend_Auth_Storage_Interface
- {
- /**
- * Returns true if and only if storage is empty
- *
- * @throws Zend_Auth_Storage_Exception If it is impossible to
- * determine whether storage
- * is empty
- * @return boolean
- */
- public function isEmpty()
- {
- /**
- * @todo implementation
- */
- }
- /**
- * Returns the contents of storage
- *
- * 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 implementation
- */
- }
- /**
- * Writes $contents to storage
- *
- * @param mixed $contents
- * @throws Zend_Auth_Storage_Exception If writing $contents to
- * storage is impossible
- * @return void
- */
- public function write($contents)
- {
- /**
- * @todo implementation
- */
- }
- /**
- * Clears contents from storage
- *
- * @throws Zend_Auth_Storage_Exception If clearing contents from
- * storage is impossible
- * @return void
- */
- public function clear()
- {
- /**
- * @todo implementation
- */
- }
- }
- ]]></programlisting>
- </para>
- <para>
- In order to use this custom storage class, <classname>Zend_Auth::setStorage()</classname> is invoked before an
- authentication query is attempted:
- <programlisting role="php"><![CDATA[
- // Instruct Zend_Auth to use the custom storage class
- Zend_Auth::getInstance()->setStorage(new MyStorage());
- /**
- * @todo Set up the auth adapter, $authAdapter
- */
- // Authenticate, saving the result, and persisting the identity on
- // success
- $result = Zend_Auth::getInstance()->authenticate($authAdapter);
- ]]></programlisting>
- </para>
- </example>
- </sect3>
- </sect2>
- <sect2 id="zend.auth.introduction.using">
- <title>Usage</title>
- <para>
- There are two provided ways to use <classname>Zend_Auth</classname> adapters:
- <orderedlist>
- <listitem>
- <para>
- indirectly, through <classname>Zend_Auth::authenticate()</classname>
- </para>
- </listitem>
- <listitem>
- <para>
- directly, through the adapter's <code>authenticate()</code> method
- </para>
- </listitem>
- </orderedlist>
- </para>
- <para>
- The following example illustrates how to use a <classname>Zend_Auth</classname> adapter indirectly, through the use of
- the <classname>Zend_Auth</classname> class:
- <programlisting role="php"><![CDATA[
- // Get a reference to the singleton instance of Zend_Auth
- $auth = Zend_Auth::getInstance();
- // Set up the authentication adapter
- $authAdapter = new MyAuthAdapter($username, $password);
- // Attempt authentication, saving the result
- $result = $auth->authenticate($authAdapter);
- if (!$result->isValid()) {
- // Authentication failed; print the reasons why
- foreach ($result->getMessages() as $message) {
- echo "$message\n";
- }
- } else {
- // Authentication succeeded; the identity ($username) is stored
- // in the session
- // $result->getIdentity() === $auth->getIdentity()
- // $result->getIdentity() === $username
- }
- ]]></programlisting>
- </para>
- <para>
- Once authentication has been attempted in a request, as in the above example, it is a simple
- matter to check whether a successfully authenticated identity exists:
- <programlisting role="php"><![CDATA[
- $auth = Zend_Auth::getInstance();
- if ($auth->hasIdentity()) {
- // Identity exists; get it
- $identity = $auth->getIdentity();
- }
- ]]></programlisting>
- </para>
- <para>
- To remove an identity from persistent storage, simply use the <code>clearIdentity()</code> method.
- This typically would be used for implementing an application "logout" operation:
- <programlisting role="php"><![CDATA[
- Zend_Auth::getInstance()->clearIdentity();
- ]]></programlisting>
- </para>
- <para>
- When the automatic use of persistent storage is inappropriate for a particular use case, a
- developer may simply bypass the use of the <classname>Zend_Auth</classname> class, using an adapter class
- directly. Direct use of an adapter class involves configuring and preparing an adapter object and
- then calling its <code>authenticate()</code> method. Adapter-specific details are discussed in the
- documentation for each adapter. The following example directly utilizes
- <code>MyAuthAdapter</code>:
- <programlisting role="php"><![CDATA[
- // Set up the authentication adapter
- $authAdapter = new MyAuthAdapter($username, $password);
- // Attempt authentication, saving the result
- $result = $authAdapter->authenticate();
- if (!$result->isValid()) {
- // Authentication failed; print the reasons why
- foreach ($result->getMessages() as $message) {
- echo "$message\n";
- }
- } else {
- // Authentication succeeded
- // $result->getIdentity() === $username
- }
- ]]></programlisting>
- </para>
- </sect2>
- </sect1>
- <!--
- vim:se ts=4 sw=4 et:
- -->
|