Zend_Auth_Adapter_DbTable.xml 14 KB

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