Zend_Auth_Adapter_DbTable.xml 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- EN-Revision: 17175 -->
  3. <!-- Reviewed: no -->
  4. <sect1 id="zend.auth.adapter.dbtable">
  5. <title>Tabla de base de datos de autenticación</title>
  6. <sect2 id="zend.auth.adapter.dbtable.introduction">
  7. <title>Introducción</title>
  8. <para>
  9. <classname>Zend_Auth_Adapter_DbTable</classname> proporciona la
  10. capacidad de autenticar contra credenciales almacenadas en una tabla
  11. de la base de datos. Como
  12. <classname>Zend_Auth_Adapter_DbTable</classname> requiere una
  13. instancia de <classname>Zend_Db_Adapter_Abstract</classname> que
  14. será pasada a su constructor, cada instancia está vinculada a una
  15. conexión concreta de la base de datos. Se pueden establecer otras
  16. opciones de configuración a través del constructor y de métodos de
  17. instancia: </para>
  18. <para> Las opciones de configuración disponibles incluyen:
  19. </para>
  20. <itemizedlist>
  21. <listitem>
  22. <para>
  23. <emphasis><property>tableName</property></emphasis>: Nombre de tabla de
  24. la base de datos que contiene las credenciales de
  25. autenticación, y contra la cual se realiza la búsqueda
  26. de autenticación en la base de datos. </para>
  27. </listitem>
  28. <listitem>
  29. <para>
  30. <emphasis><property>identityColumn</property></emphasis>: Nombre de la
  31. columna de la tabla de la base de datos utilizada para
  32. representar la identidad. La columna identidad debe
  33. contar con valores únicos, tales como un apellido ó una
  34. dirección de e-mail. </para>
  35. </listitem>
  36. <listitem>
  37. <para>
  38. <emphasis><property>credentialColumn</property></emphasis>: Nombre de la
  39. columna de la tabla de la base de datos utilizada para
  40. representar la credencial. Conforme a un sistema de
  41. identidad simple y autenticación de contraseña, el valor
  42. de la credencial corresponde con la contraseña. Véase
  43. también la opción <property>credentialTreatment
  44. </property>. </para>
  45. </listitem>
  46. <listitem>
  47. <para>
  48. <emphasis><property>credentialTreatment</property></emphasis>: En muchos
  49. casos, contraseñas y otros datos son encriptados,
  50. mezclados, codificados, ocultados, desplazados o
  51. tratados de otra manera a través de alguna función o
  52. algoritmo. Al especificar una cadena de tratamiento
  53. parametrizada con este método, tal como
  54. <methodname>'MD5(?)'</methodname> o
  55. <methodname>'PASSWORD(?)'</methodname>, un
  56. desarrollador podría aplicar sentencias arbitrarias <acronym>SQL</acronym>
  57. sobre los datos credenciales de entrada. Ya que estas
  58. funciones son específicas de los <acronym>RDBMS</acronym>, debemos
  59. consultar el manual de la base de datos para comprobar
  60. la disponibilidad de tales funciones para su sistema de
  61. base de datos.
  62. </para>
  63. </listitem>
  64. </itemizedlist>
  65. <example id="zend.auth.adapter.dbtable.introduction.example.basic_usage">
  66. <title>Uso Básico</title>
  67. <para> Como se explicó en la introducción, el constructor
  68. <classname>Zend_Auth_Adapter_DbTable</classname> requiere
  69. una instancia de <classname>Zend_Db_Adapter_Abstract</classname>
  70. que sirve como conexión a la base de datos a la cual la
  71. instancia de autenticación está obligada a adaptarse. En primer
  72. lugar, la conexión de la base de datos debe ser creada. </para>
  73. <para> El siguiente código crea un adaptador para una base de datos
  74. en memoria , un esquema simple de la tabla, e inserta una fila
  75. contra la que se pueda realizar una consulta de autenticación
  76. posterior. Este ejemplo requiere que la extensión <acronym>PDO</acronym> SQLite
  77. esté disponible. </para>
  78. <programlisting language="php"><![CDATA[
  79. // Crear una conexión en memoria de la bade de datos SQLite
  80. $dbAdapter = new Zend_Db_Adapter_Pdo_Sqlite(array('dbname' =>
  81. ':memory:'));
  82. // Construir mediante una consulta una simple tabla
  83. $sqlCreate = 'CREATE TABLE [users] ('
  84. . '[id] INTEGER NOT NULL PRIMARY KEY, '
  85. . '[username] VARCHAR(50) UNIQUE NOT NULL, '
  86. . '[password] VARCHAR(32) NULL, '
  87. . '[real_name] VARCHAR(150) NULL)';
  88. // Crear las credenciales de autenticación de la tabla
  89. $dbAdapter->query($sqlCreate);
  90. // Construir una consulta para insertar una fila para que se pueda realizar la autenticación
  91. $sqlInsert = "INSERT INTO users (username, password, real_name) "
  92. . "VALUES ('my_username', 'my_password', 'My Real Name')";
  93. // Insertar los datos
  94. $dbAdapter->query($sqlInsert);
  95. ]]></programlisting>
  96. <para> Con la conexión de la base de datos y los datos de la tabla
  97. disponibles, podemos crear un instancia de
  98. <classname>Zend_Auth_Adapter_DbTable</classname>. Los
  99. valores de las opciones de configuración pueden ser pasados al
  100. constructor o pasados como parámetros a los métodos setter
  101. después de ser instanciados. </para>
  102. <programlisting language="php"><![CDATA[
  103. // Configurar la instancia con los parámetros del constructor...
  104. $authAdapter = new Zend_Auth_Adapter_DbTable(
  105. $dbAdapter,
  106. 'users',
  107. 'username',
  108. 'password'
  109. );
  110. // ...o configurar la instancia con los métodos setter.
  111. $authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);
  112. $authAdapter
  113. ->setTableName('users')
  114. ->setIdentityColumn('username')
  115. ->setCredentialColumn('password')
  116. ;
  117. ]]></programlisting>
  118. <para> En este punto, el adaptador de la instancia de autenticación
  119. está listo para aceptar consultas de autenticación. Con el fin
  120. de elaborar una consulta de autenticación, los valores de
  121. entrada de la credencial son pasados por el adaptador ates de
  122. llamar al método <methodname>authenticate()</methodname>: </para>
  123. <programlisting language="php"><![CDATA[
  124. // Seleccionamos los valores de entrada de la credencial (e.g., de un formulario de acceso)
  125. $authAdapter
  126. ->setIdentity('my_username')
  127. ->setCredential('my_password')
  128. ;
  129. // Ejecutamos la consulta de autenticación, salvando los resultados
  130. ]]></programlisting>
  131. <para> Además de la disponibilidad del método
  132. <methodname>getIdentity()</methodname> sobre el objeto
  133. resultante de la autenticación,
  134. <classname>Zend_Auth_Adapter_DbTable</classname> también
  135. ayuda a recuperar la fila de al tabla sobre la autenticación
  136. realizada. </para>
  137. <programlisting language="php"><![CDATA[
  138. // Imprimir la identidad
  139. echo $result->getIdentity() . "\n\n";
  140. // Imprimir la fila resultado
  141. print_r($authAdapter->getResultRowObject());
  142. /* Salida:
  143. my_username
  144. Array
  145. (
  146. [id] => 1
  147. [username] => my_username
  148. [password] => my_password
  149. [real_name] => My Real Name
  150. )
  151. ]]></programlisting>
  152. <para> Ya que la fila de la tabla contiene el valor de la
  153. credencial, es importante proteger los valores contra accesos no
  154. deseados. </para>
  155. </example>
  156. </sect2>
  157. <sect2 id="zend.auth.adapter.dbtable.advanced.storing_result_row">
  158. <title>Advanced Usage: Manteniendo el resultado del Objeto
  159. DbTable</title>
  160. <para> Por defecto, <classname>Zend_Auth_Adapter_DbTable</classname>
  161. devuelve la identidad proporcionada al objeto Auth en la
  162. autenticación realizada. Otro de los casos de uso, donde los
  163. desarrolladores desean guardar para mantener el mecanismo de
  164. almacenamiento de un objeto identidad
  165. <classname>Zend_Auth</classname> que contiene información útil,
  166. se resuelve usando el método
  167. <methodname>getResultRowObject()</methodname> para devolver un
  168. objeto <emphasis>stdClass</emphasis>. El siguiente fragmento de
  169. código muestra su uso: </para>
  170. <programlisting language="php"><![CDATA[
  171. // Autenticar con Zend_Auth_Adapter_DbTable
  172. $result = $this->_auth->authenticate($adapter);
  173. if ($result->isValid()) {
  174. // Almacena la identidad como un objedo dónde solo username y
  175. // real_name han sido devueltos
  176. $storage = $this->_auth->getStorage();
  177. $storage->write($adapter->getResultRowObject(array(
  178. 'username',
  179. 'real_name',
  180. )));
  181. // Almacena la identidad como un objeto dónde la columna contraseña ha
  182. // sido omitida
  183. $storage->write($adapter->getResultRowObject(
  184. null,
  185. 'password'
  186. ));
  187. /* ... */
  188. } else {
  189. /* ... */
  190. }
  191. ]]></programlisting>
  192. </sect2>
  193. <sect2 id="zend.auth.adapter.dbtable.advanced.advanced_usage">
  194. <title>Ejemplo de Uso Avanzado</title>
  195. <para> Si bien el objetivo primordial de
  196. <classname>Zend_Auth</classname> (y, por consiguiente,
  197. <classname>Zend_Auth_Adapter_DbTable</classname>) es
  198. principalmente la <emphasis>autenticación</emphasis> y no la
  199. <emphasis>autorización</emphasis>, hay unos pocos casos y
  200. problemas que se encuentran al límite entre cuales encajan dentro
  201. del dominio. Dependiendo de cómo haya decidido explicar su problema,
  202. a veces tiene sentido resolver lo que podría parecer un problema de
  203. autorización dentro de un adaptador de autenticación. </para>
  204. <para> Con esa excepción fuera de lo común,
  205. <classname>Zend_Auth_Adapter_DbTable</classname> ha construido
  206. mecanismos que pueden ser aprovechados para realizar controles
  207. adicionales en la autenticación a la vez que se resuelven algunos
  208. problemas comunes de los usuarios. </para>
  209. <programlisting language="php"><![CDATA[
  210. // El valor del campo status de una cuenta no es igual a "compromised"
  211. $adapter = new Zend_Auth_Adapter_DbTable(
  212. $db,
  213. 'users',
  214. 'username',
  215. 'password',
  216. 'MD5(?) AND status != "compromised"'
  217. );
  218. // El valor del campo active de una cuenta es igual a "TRUE"
  219. $adapter = new Zend_Auth_Adapter_DbTable(
  220. $db,
  221. 'users',
  222. 'username',
  223. 'password',
  224. 'MD5(?) AND active = "TRUE"'
  225. ]]></programlisting>
  226. <para> Otra idea puede ser la aplicación de un mecanismo de "salting".
  227. "Salting" es un término que se refiere a una técnica que puede
  228. mejorar altamente la seguridad de su aplicación. Se basa en la idea
  229. de concatenar una cadena aleatoria a cada contraseña para evitar un
  230. ataque de fuerza bruta sobre la base de datos usando los valores
  231. hash de un diccionario pre-calculado. </para>
  232. <para> Por lo tanto, tenemos que modificar nuestra tabla para almacenar
  233. nuestra cadena mezclada: </para>
  234. <programlisting language="php"><![CDATA[
  235. $sqlAlter = "ALTER TABLE [users] "
  236. . "ADD COLUMN [password_salt] "
  237. . "AFTER [password]";
  238. ]]></programlisting>
  239. <para> Aquí hay una forma sencilla de generar una cadena mezclada por
  240. cada usuario en el momento del registro: </para>
  241. <programlisting language="php"><![CDATA[
  242. for ($i = 0; $i < 50; $i++) {
  243. $dynamicSalt .= chr(rand(33, 126));
  244. ]]></programlisting>
  245. <para> Y ahora vamos a construir el adaptador: </para>
  246. <programlisting language="php"><![CDATA[
  247. $adapter = new Zend_Auth_Adapter_DbTable(
  248. $db,
  249. 'users',
  250. 'username',
  251. 'password',
  252. "MD5(CONCAT('"
  253. . Zend_Registry::get('staticSalt')
  254. . "', ?, password_salt))"
  255. );
  256. ]]></programlisting>
  257. <note>
  258. <para> Puede mejorar aún más la seguridad mediante el uso de un
  259. valor 'salt' estático fuertemente codificado en su aplicación.
  260. En el caso de que su base de datos se vea comprometida (por
  261. ejemplo, por un ataque de inyección <acronym>SQL</acronym>), su servidor web está
  262. intacto y sus datos son inutilizable para el atacante. </para>
  263. </note>
  264. <para> Otra alternativa es utilizar el método
  265. <methodname>getDbSelect()</methodname> de
  266. <classname>Zend_Auth_Adapter_DbTable</classname> después de que el adaptador se ha
  267. construido. Este método devolverá la instancia del objeto
  268. <classname>Zend_Db_Select</classname> que se va a utilizar para completar la rutina de
  269. authenticate(). Es importante señalar que este método siempre
  270. devuelve el mismo objeto, independientemente de si <methodname>authenticate()</methodname> ha
  271. sido llamado o no. Este objeto <emphasis>no tendrá</emphasis>
  272. ninguna de las credenciales de identidad o información de como estos
  273. valores son colocados dentro del objeto seleccionado en
  274. <methodname>authenticate()</methodname>. </para>
  275. <para> Un ejemplo de una situación en la que uno podría querer utilizar
  276. el método <methodname>getDbSelect()</methodname> sería comprobar el estado de un usuario, en
  277. otras palabras, ver si la cuenta del usuario está habilitada. </para>
  278. <programlisting language="php"><![CDATA[
  279. // Continuando con el ejemplo de arriba
  280. $adapter = new Zend_Auth_Adapter_DbTable(
  281. $db,
  282. 'users',
  283. 'username',
  284. 'password',
  285. 'MD5(?)'
  286. );
  287. // obtener el objeto select (por referencia)
  288. $select = $adapter->getDbSelect();
  289. $select->where('active = "TRUE"');
  290. // authenticate, esto asegura que users.active = TRUE
  291. $adapter->authenticate();
  292. ]]></programlisting>
  293. </sect2>
  294. </sect1>