| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- EN-Revision: 17175 -->
- <!-- 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:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <emphasis>
- <property>tableName</property>
- </emphasis>
- : 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>
- <emphasis>
- <property>identityColumn</property>
- </emphasis>
- : 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>
- <emphasis>
- <property>credentialColumn</property>
- </emphasis>
- : 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
- <property>credentialTreatment
- </property>
- .
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>
- <property>credentialTreatment</property>
- </emphasis>
- : 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
- <methodname>'MD5(?)'</methodname>
- o
- <methodname>'PASSWORD(?)'</methodname>
- , un
- desarrollador podría aplicar sentencias arbitrarias
- <acronym>SQL</acronym>
- sobre los datos credenciales de entrada. Ya que estas
- funciones son específicas de los
- <acronym>RDBMS</acronym>
- , 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>
- <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
- <acronym>PDO</acronym>
- SQLite
- esté disponible.
- </para>
- <programlisting language="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 language="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
- <methodname>authenticate()</methodname>
- :
- </para>
- <programlisting language="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
- <methodname>getIdentity()</methodname>
- 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 language="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
- <methodname>getResultRowObject()</methodname>
- para devolver un
- objeto
- <emphasis>stdClass</emphasis>
- . El siguiente fragmento de
- código muestra su uso:
- </para>
- <programlisting language="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 language="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 language="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 language="php"><![CDATA[
- for ($i = 0; $i < 50; $i++) {
- $dynamicSalt .= chr(rand(33, 126));
- ]]></programlisting>
- <para>Y ahora vamos a construir el adaptador:</para>
- <programlisting language="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
- <acronym>SQL</acronym>
- ), su servidor web está
- intacto y sus datos son inutilizable para el atacante.
- </para>
- </note>
- <para>
- Otra alternativa es utilizar el método
- <methodname>getDbSelect()</methodname>
- de
- <classname>Zend_Auth_Adapter_DbTable</classname>
- después de que el adaptador se ha
- construido. Este método devolverá la instancia del
- objeto
- <classname>Zend_Db_Select</classname>
- 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
- <methodname>authenticate()</methodname>
- 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
- <methodname>authenticate()</methodname>
- .
- </para>
- <para>
- Un ejemplo de una situación en la que uno podría querer utilizar
- el método
- <methodname>getDbSelect()</methodname>
- sería comprobar el estado de un usuario, en
- otras palabras, ver si la cuenta del usuario
- está habilitada.
- </para>
- <programlisting language="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>
|