| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- Reviewed: no -->
- <sect1 id="zend.auth.adapter.dbtable">
- <title>Tabla de base de datos de autenticación</title>
- <sect2 id="zend.auth.adapter.dbtable.introduction">
- <title>Introducción</title>
- <para>
- <classname>Zend_Auth_Adapter_DbTable</classname> proporciona la capacidad
- de autenticar contra credenciales almacenadas en una tabla de la base de
- datos. Como <classname>Zend_Auth_Adapter_DbTable</classname> requiere una
- instancia de <classname>Zend_Db_Adapter_Abstract</classname> que será
- pasada a su constructor, cada instancia está vinculada a una conexión
- concreta de la base de datos. Se pueden establecer otras opciones de
- configuración a través del constructor y de métodos de instancia:
- </para>
- <para>
- Las opciones de configuración disponibles incluyen:
- <itemizedlist>
- <listitem>
- <para>
- <code>tableName</code>: Nombre de tabla de la base de datos que
- contiene las credenciales de autenticación, y contra la cual
- se realiza la búsqueda de autenticación en la base de datos.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>identityColumn</code>: Nombre de la columna de la tabla
- de la base de datos utilizada para representar la identidad. La
- columna identidad debe contar con valores únicos, tales como un
- apellido ó una dirección de e-mail.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>credentialColumn</code>: Nombre de la columna de la tabla
- de la base de datos utilizada para representar la credencial.
- Conforme a un sistema de identidad simple y autenticación de
- contraseña, el valor de la credencial corresponde con la
- contraseña. Véase también la opción <code>credentialTreatment
- </code>.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>credentialTreatment</code>: En muchos casos, contraseñas
- y otros datos son encriptados, mezclados, codificados,
- ocultados, desplazados o tratados de otra manera a través de
- alguna función o algoritmo. Al especificar una cadena de
- tratamiento parametrizada con este método, tal como
- <code>'MD5(?)'</code> o <code>'PASSWORD(?)'</code>, un
- desarrollador podría aplicar sentencias arbitrarias SQL
- sobre los datos credenciales de entrada. Ya que estas funciones
- son específicas de los RDBMS, debemos consultar el manual de la
- base de datos para comprobar la disponibilidad de tales
- funciones para su sistema de base de datos.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- <example id="zend.auth.adapter.dbtable.introduction.example.basic_usage">
- <title>Uso Básico</title>
- <para>
- Como se explicó en la introducción, el constructor
- <classname>Zend_Auth_Adapter_DbTable</classname> requiere una instancia
- de <classname>Zend_Db_Adapter_Abstract</classname> que sirve como
- conexión a la base de datos a la cual la instancia de autenticación
- está obligada a adaptarse. En primer lugar, la conexión de la base de
- datos debe ser creada.
- </para>
- <para>
- El siguiente código crea un adaptador para una base de datos en memoria
- , un esquema simple de la tabla, e inserta una fila contra la que se
- pueda realizar una consulta de autenticación posterior. Este ejemplo
- requiere que la extensión DOP SQLite esté disponible.
- </para>
- <programlisting role="php"><![CDATA[
- // Crear una conexión en memoria de la bade de datos SQLite
- $dbAdapter = new Zend_Db_Adapter_Pdo_Sqlite(array('dbname' =>
- ':memory:'));
- // Construir mediante una consulta una simple tabla
- $sqlCreate = 'CREATE TABLE [users] ('
- . '[id] INTEGER NOT NULL PRIMARY KEY, '
- . '[username] VARCHAR(50) UNIQUE NOT NULL, '
- . '[password] VARCHAR(32) NULL, '
- . '[real_name] VARCHAR(150) NULL)';
- // Crear las credenciales de autenticación de la tabla
- $dbAdapter->query($sqlCreate);
- // Construir una consulta para insertar una fila para que se pueda realizar la autenticación
- $sqlInsert = "INSERT INTO users (username, password, real_name) "
- . "VALUES ('my_username', 'my_password', 'My Real Name')";
- // Insertar los datos
- $dbAdapter->query($sqlInsert);
- ]]></programlisting>
- <para>
- Con la conexión de la base de datos y los datos de la tabla
- disponibles, podemos crear un instancia de
- <classname>Zend_Auth_Adapter_DbTable</classname>. Los valores de las opciones
- de configuración pueden ser pasados al constructor o pasados como
- parámetros a los métodos setter después de ser instanciados.
- </para>
- <programlisting role="php"><![CDATA[
- // Configurar la instancia con los parámetros del constructor...
- $authAdapter = new Zend_Auth_Adapter_DbTable(
- $dbAdapter,
- 'users',
- 'username',
- 'password'
- );
- // ...o configurar la instancia con los métodos setter.
- $authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);
- $authAdapter
- ->setTableName('users')
- ->setIdentityColumn('username')
- ->setCredentialColumn('password')
- ;
- ]]></programlisting>
- <para>
- En este punto, el adaptador de la instancia de autenticación está listo
- para aceptar consultas de autenticación. Con el fin de elaborar una
- consulta de autenticación, los valores de entrada de la credencial son
- pasados por el adaptador ates de llamar al método
- <code>authenticate()</code>:
- </para>
- <programlisting role="php"><![CDATA[
- // Seleccionamos los valores de entrada de la credencial (e.g., de un formulario de acceso)
- $authAdapter
- ->setIdentity('my_username')
- ->setCredential('my_password')
- ;
- // Ejecutamos la consulta de autenticación, salvando los resultados
- ]]></programlisting>
- <para>
- Además de la disponibilidad del método <code>getIdentity()</code>
- sobre el objeto resultante de la autenticación,
- <classname>Zend_Auth_Adapter_DbTable</classname> también ayuda a
- recuperar la fila de al tabla sobre la autenticación realizada.
- </para>
- <programlisting role="php"><![CDATA[
- // Imprimir la identidad
- echo $result->getIdentity() . "\n\n";
- // Imprimir la fila resultado
- print_r($authAdapter->getResultRowObject());
- /* Salida:
- my_username
- Array
- (
- [id] => 1
- [username] => my_username
- [password] => my_password
- [real_name] => My Real Name
- )
- ]]></programlisting>
- <para>
- Ya que la fila de la tabla contiene el valor de la credencial, es
- importante proteger los valores contra accesos no deseados.
- </para>
- </example>
- </sect2>
- <sect2 id="zend.auth.adapter.dbtable.advanced.storing_result_row">
- <title>Advanced Usage: Manteniendo el resultado del Objeto DbTable</title>
- <para>
- Por defecto, <classname>Zend_Auth_Adapter_DbTable</classname> devuelve la
- identidad proporcionada al objeto Auth en la autenticación
- realizada. Otro de los casos de uso, donde los desarrolladores desean
- guardar para mantener el mecanismo de almacenamiento de un objeto identidad
- <classname>Zend_Auth</classname> que contiene información útil, se
- resuelve usando el método <code>getResultRowObject()</code> para devolver
- un objeto <code>stdClass</code>. El siguiente fragmento de código muestra
- su uso:
- </para>
- <programlisting role="php"><![CDATA[
- // Autenticar con Zend_Auth_Adapter_DbTable
- $result = $this->_auth->authenticate($adapter);
- if ($result->isValid()) {
- // Almacena la identidad como un objedo dónde solo username y
- // real_name han sido devueltos
- $storage = $this->_auth->getStorage();
- $storage->write($adapter->getResultRowObject(array(
- 'username',
- 'real_name',
- )));
- // Almacena la identidad como un objeto dónde la columna contraseña ha
- // sido omitida
- $storage->write($adapter->getResultRowObject(
- null,
- 'password'
- ));
- /* ... */
- } else {
- /* ... */
- }
- ]]></programlisting>
- </sect2>
- <sect2 id="zend.auth.adapter.dbtable.advanced.advanced_usage">
- <title>Ejemplo de Uso Avanzado</title>
- <para>
- Si bien el objetivo primordial de <classname>Zend_Auth</classname> (y,
- por consiguiente, <classname>Zend_Auth_Adapter_DbTable</classname>) es
- principalmente la <emphasis>autenticación</emphasis> y no
- la <emphasis>autorización</emphasis>, hay unos pocos casos
- y problemas que se encuentran al límite entre cuales encajan dentro del
- dominio.
- Dependiendo de cómo haya decidido explicar su problema, a veces tiene
- sentido resolver lo que podría parecer un problema de autorización
- dentro de un adaptador de autenticación.
- </para>
- <para>
- Con esa excepción fuera de lo común,
- <classname>Zend_Auth_Adapter_DbTable</classname> ha construido mecanismos
- que pueden ser aprovechados para realizar controles adicionales en la
- autenticación a la vez que se resuelven algunos problemas comunes de los
- usuarios.
- </para>
- <programlisting role="php"><![CDATA[
- // El valor del campo status de una cuenta no es igual a "compromised"
- $adapter = new Zend_Auth_Adapter_DbTable(
- $db,
- 'users',
- 'username',
- 'password',
- 'MD5(?) AND status != "compromised"'
- );
- // El valor del campo active de una cuenta es igual a "TRUE"
- $adapter = new Zend_Auth_Adapter_DbTable(
- $db,
- 'users',
- 'username',
- 'password',
- 'MD5(?) AND active = "TRUE"'
- ]]></programlisting>
- <para>
- Otra idea puede ser la aplicación de un mecanismo de "salting". "Salting"
- es un término que se refiere a una técnica que puede mejorar altamente la
- seguridad de su aplicación. Se basa en la idea de concatenar una cadena
- aleatoria a cada contraseña para evitar un ataque de fuerza bruta sobre la
- base de datos usando los valores hash de un diccionario pre-calculado.
- </para>
- <para>
- Por lo tanto, tenemos que modificar nuestra tabla para almacenar nuestra
- cadena mezclada:
- </para>
- <programlisting role="php"><![CDATA[
- $sqlAlter = "ALTER TABLE [users] "
- . "ADD COLUMN [password_salt] "
- . "AFTER [password]";
- ]]></programlisting>
- <para>
- Aquí hay una forma sencilla de generar una cadena mezclada por cada
- usuario en el momento del registro:
- </para>
- <programlisting role="php"><![CDATA[
- for ($i = 0; $i < 50; $i++) {
- $dynamicSalt .= chr(rand(33, 126));
- ]]></programlisting>
- <para>
- Y ahora vamos a construir el adaptador:
- </para>
- <programlisting role="php"><![CDATA[
- $adapter = new Zend_Auth_Adapter_DbTable(
- $db,
- 'users',
- 'username',
- 'password',
- "MD5(CONCAT('"
- . Zend_Registry::get('staticSalt')
- . "', ?, password_salt))"
- );
- ]]></programlisting>
- <note>
- <para>
- Puede mejorar aún más la seguridad mediante el uso de un valor
- 'salt' estático fuertemente codificado en su aplicación. En el caso de
- que su base de datos se vea comprometida (por ejemplo, por un ataque
- de inyección SQL), su servidor web está intacto y sus
- datos son inutilizable para el atacante.
- </para>
- </note>
- <para>
- Otra alternativa es utilizar el método <code>getDbSelect()</code> de
- Zend_Auth_Adapter_DbTable después de que el adaptador se ha construido.
- Este método devolverá la instancia del objeto Zend_Db_Select que se va a
- utilizar para completar la rutina de authenticate(). Es importante señalar
- que este método siempre devuelve el mismo objeto, independientemente de si
- authenticate() ha sido llamado o no. Este objeto
- <emphasis>no tendrá</emphasis> ninguna de las
- credenciales de identidad o información de como estos valores son colocados
- dentro del objeto seleccionado en authenticate().
- </para>
- <para>
- Un ejemplo de una situación en la que uno podría querer utilizar el
- método getDbSelect() sería comprobar el estado de un usuario, en otras
- palabras, ver si la cuenta del usuario está habilitada.
- </para>
- <programlisting role="php"><![CDATA[
- // Continuando con el ejemplo de arriba
- $adapter = new Zend_Auth_Adapter_DbTable(
- $db,
- 'users',
- 'username',
- 'password',
- 'MD5(?)'
- );
- // obtener el objeto select (por referencia)
- $select = $adapter->getDbSelect();
- $select->where('active = "TRUE"');
- // authenticate, esto asegura que users.active = TRUE
- $adapter->authenticate();
- ]]></programlisting>
- </sect2>
- </sect1>
|