Zend_Auth_Adapter_DbTable.xml 14 KB

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