Zend_Auth_Adapter_DbTable proporciona la capacidad de
autenticarse contra credenciales almacenadas en una tabla de base de datos. Debido a que
Zend_Auth_Adapter_DbTable requiere que se pase una instancia de
Zend_Db_Adapter_Abstract a su
constructor, cada instancia está vinculada a una conexión de base de datos
en particular. Otras opciones de configuración pueden establecerse mediante el
constructor y mediante métodos de instancia, uno para cada opción.
Las opciones de configuración disponibles incluyen:
tableName: Este es el nombre de la tabla de base de datos que contiene las credenciales de autenticación, y contra la cual se realiza la consulta de autenticación de la base de datos.
identityColumn: Este es el nombre de la columna de la tabla de base de datos utilizada para representar la identidad. La columna de identidad debe contener valores únicos, tales como un nombre de usuario o dirección de correo electrónico.
credentialColumn: Este es el nombre de la columna de la tabla de base de datos utilizada para representar la credencial. Bajo un esquema simple de autenticación de identidad y contraseña, el valor de la credencial corresponde a la contraseña. Vea también la opción credentialTreatment.
credentialTreatment: En muchos casos, las contraseñas y otros datos sensibles se cifran, aplican hash, codifican, ofuscan, salan u otramente se tratan mediante alguna función o algoritmo. Al especificar una cadena de tratamiento parametrizada con este método, tal como '
MD5(?)' o 'PASSWORD(?)', un desarrollador puede aplicar dicho SQL arbitrario sobre los datos de credencial de entrada. Dado que estas funciones son específicas del RDBMS subyacente, consulte el manual de la base de datos para conocer la disponibilidad de dichas funciones para su sistema de base de datos.
Ejemplo 15.3. Uso básico
Como se explicó en la introducción, el
constructor de Zend_Auth_Adapter_DbTable requiere una
instancia de Zend_Db_Adapter_Abstract que sirva como
la conexión de base de datos a la cual está vinculada la instancia del adaptador
de autenticación. Primero, se debe crear la conexión de base de datos.
El siguiente código crea un adaptador para una base de datos en memoria, crea un esquema de tabla simple, e inserta una fila contra la cual podemos realizar una consulta de autenticación posteriormente. Este ejemplo requiere que la extensión PDO SQLite esté disponible:
// Create an in-memory SQLite database connection
$dbAdapter = new Zend_Db_Adapter_Pdo_Sqlite(array('dbname' =>
':memory:'));
// Build a simple table creation query
$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)';
// Create the authentication credentials table
$dbAdapter->query($sqlCreate);
// Build a query to insert a row for which authentication may succeed
$sqlInsert = "INSERT INTO users (username, password, real_name) "
. "VALUES ('my_username', 'my_password', 'My Real Name')";
// Insert the data
$dbAdapter->query($sqlInsert);
Con la conexión de base de datos y los datos de la tabla disponibles, se puede
crear una instancia de Zend_Auth_Adapter_DbTable. Los valores de las
opciones de configuración pueden pasarse al
constructor o diferirse como parámetros a métodos setter después
de la instanciación:
// Configure the instance with constructor parameters...
$authAdapter = new Zend_Auth_Adapter_DbTable(
$dbAdapter,
'users',
'username',
'password'
);
// ...or configure the instance with setter methods
$authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);
$authAdapter
->setTableName('users')
->setIdentityColumn('username')
->setCredentialColumn('password')
;
En este punto, la instancia del adaptador de autenticación está lista para
aceptar consultas de autenticación. Para formular una
consulta de autenticación, los valores de credencial de entrada se pasan al
adaptador antes de llamar al método authenticate():
// Set the input credential values (e.g., from a login form)
$authAdapter
->setIdentity('my_username')
->setCredential('my_password')
;
// Perform the authentication query, saving the result
Además de la disponibilidad del método getIdentity()
en el objeto de resultado de autenticación, Zend_Auth_Adapter_DbTable
también admite la recuperación de la fila de la tabla al lograr la autenticación:
// Print the identity
echo $result->getIdentity() . "\n\n";
// Print the result row
print_r($authAdapter->getResultRowObject());
/* Output:
my_username
Array
(
[id] => 1
[username] => my_username
[password] => my_password
[real_name] => My Real Name
)
Dado que la fila de la tabla contiene el valor de la credencial, es importante asegurar los valores contra el acceso no deseado.
Por defecto, Zend_Auth_Adapter_DbTable devuelve al objeto auth la
identidad proporcionada tras una
autenticación exitosa. Otro caso de uso, en el que los desarrolladores desean
almacenar en el mecanismo de almacenamiento persistente de Zend_Auth
un objeto de identidad que contenga otra información útil, se resuelve
usando el método getResultRowObject() para devolver un
objeto stdClass. El siguiente fragmento de código ilustra
su uso:
// authenticate with Zend_Auth_Adapter_DbTable
$result = $this->_auth->authenticate($adapter);
if ($result->isValid()) {
// store the identity as an object where only the username and
// real_name have been returned
$storage = $this->_auth->getStorage();
$storage->write($adapter->getResultRowObject(array(
'username',
'real_name',
)));
// store the identity as an object where the password column has
// been omitted
$storage->write($adapter->getResultRowObject(
null,
'password'
));
/* ... */
} else {
/* ... */
}
Si bien el propósito principal de Zend_Auth (y por consiguiente
de Zend_Auth_Adapter_DbTable) es principalmente la
autenticación y no
la autorización, hay
algunas instancias y problemas que rozan la línea entre a qué dominio pertenecen.
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 del adaptador de autenticación.
Con esa aclaración fuera del camino, Zend_Auth_Adapter_DbTable
tiene algunos mecanismos incorporados que pueden aprovecharse para verificaciones adicionales en el
momento de la autenticación para resolver algunos problemas comunes de los usuarios.
// The status field value of an account is not equal to "compromised"
$adapter = new Zend_Auth_Adapter_DbTable(
$db,
'users',
'username',
'password',
'MD5(?) AND status != "compromised"'
);
// The active field value of an account is equal to "TRUE"
$adapter = new Zend_Auth_Adapter_DbTable(
$db,
'users',
'username',
'password',
'MD5(?) AND active = "TRUE"'
Otro escenario puede ser la implementación de un mecanismo de "salting" (salado). El salado es un término que se refiere a una técnica que puede mejorar en gran medida la seguridad de su aplicación. Se basa en la idea de que concatenar una cadena aleatoria a cada contraseña hace que sea imposible lograr un ataque de fuerza bruta exitoso en la base de datos usando valores de hash precalculados de un diccionario.
Por lo tanto, necesitamos modificar nuestra tabla para almacenar nuestra cadena de sal:
$sqlAlter = "ALTER TABLE [users] "
. "ADD COLUMN [password_salt] "
. "AFTER [password]";
Aquí hay una forma sencilla de generar una cadena de sal para cada usuario en el registro:
for ($i = 0; $i < 50; $i++) {
$dynamicSalt .= chr(rand(33, 126));
Y ahora construyamos el adaptador:
$adapter = new Zend_Auth_Adapter_DbTable(
$db,
'users',
'username',
'password',
"MD5(CONCAT('"
. Zend_Registry::get('staticSalt')
. "', ?, password_salt))"
);
![]() |
Nota |
|---|---|
Puede mejorar aún más la seguridad usando un valor de sal estático codificado directamente en su aplicación. En caso de que su base de datos se vea comprometida (por ejemplo, mediante un ataque de inyección SQL) pero su servidor web permanezca intacto, sus datos seguirán siendo inutilizables para el atacante. |
Otra alternativa es usar el método getDbSelect()
de Zend_Auth_Adapter_DbTable después de que se haya construido el adaptador.
Este método devolverá la instancia del objeto Zend_Db_Select
que se utilizará para completar la rutina authenticate().
Es importante notar que este método siempre devolverá el mismo objeto sin importar
si se ha llamado o no a authenticate(). Este objeto
no tendrá ninguna de la información de identidad o credencial en él,
ya que esos valores se colocan en el objeto select en el momento de
authenticate().
Un ejemplo de una situación en la que se podría querer usar el método
getDbSelect() sería verificar el estado de un usuario, en
otras palabras, ver si la cuenta de ese usuario está habilitada.
// Continuing with the example from above
$adapter = new Zend_Auth_Adapter_DbTable(
$db,
'users',
'username',
'password',
'MD5(?)'
);
// get select object (by reference)
$select = $adapter->getDbSelect();
$select->where('active = "TRUE"');
// authenticate, this ensures that users.active = TRUE
$adapter->authenticate();
![[Note]](images/note.png)