Zend_Auth: Permitir que el usuario inicie sesión en múltiples tablas / identidades

Estoy usando Zend_Auth para autenticación en un portal web.

Una tabla mySQL normal de “usuarios” con una columna de login y password se consulta y un usuario login sesión.

Sin embargo, tengo dos grupos adicionales de usuarios que quiero autenticar. Los tres de estos grupos de usuarios tienen sus datos de inicio de sesión en otras tablas . Sus datos provienen de fonts externas, por lo que no se desea unificar estas cuentas de inicio de sesión en una sola.

Por lo tanto, podría ser que un usuario sea un usuario autenticado de cualquiera de los tres grupos, incluso los tres, al mismo tiempo .

Cada uno de los tres grupos de inicio de sesión tiene su propio formulario de inicio de sesión y de cierre de sesión.

Por el momento, tengo un solo y sencillo Zend_Auth sesión de Zend_Auth , tomado de algún tutorial y ligeramente modificado, que se ve aproximadamente así:

 function login($user, $password) { $auth = Zend_Auth::getInstance(); $storage = new Zend_Auth_Storage_Session(); $auth->setStorage($storage); $adapter = new Zend_Auth_Adapter_DbTable(....); $adapter->setIdentity($username)->setCredential($password); $result = $auth->authenticate($adapter); if ($result->isValid()) ......... success! else .... fail! 

¿Dónde tendría que comenzar a hacer este servicio y abordar estados separados “iniciados” para los tres grupos? Mi idea es que me gustaría compartir la sesión y administrar las autenticaciones por separado.

es posible? Tal vez hay un prefijo simple que hace esto fácil? ¿Existen tutoriales o recursos sobre el tema?

Soy relativamente novato en Zend Framework.

Debes crear tu propio Zend_Auth_Adapter. Este adaptador intentará autenticarse contra sus tres recursos y lo marcará en una variable de miembro privada, para que pueda saber cuáles de los bashs de inicio de sesión se han autenticado satisfactoriamente.

Para crear su Auth Adapter puede tomar como base Zend_Auth_Adapter_DbTable.

Por lo tanto, en el __construct en lugar de pasar solo un adaptador DbTable, puede pasar los tres adaptadores utilizados en cada recurso. Hará de esa manera solo si cada uno usa recursos diferentes, como LDAP, por ejemplo, o incluso otra base de datos; si no, puede pasar solo un adaptador y establecer tres nombres de tabla diferentes en las opciones de configuración.

Aquí está el ejemplo de Zend_Auth_Adapter_DbTable:

  /** * __construct() - Sets configuration options * * @param Zend_Db_Adapter_Abstract $zendDb * @param string $tableName * @param string $identityColumn * @param string $credentialColumn * @param string $credentialTreatment * @return void */ public function __construct(Zend_Db_Adapter_Abstract $zendDb, $tableName = null, $identityColumn = null, $credentialColumn = null, $credentialTreatment = null) { $this->_zendDb = $zendDb; // Here you can set three table names instead of one if (null !== $tableName) { $this->setTableName($tableName); } if (null !== $identityColumn) { $this->setIdentityColumn($identityColumn); } if (null !== $credentialColumn) { $this->setCredentialColumn($credentialColumn); } if (null !== $credentialTreatment) { $this->setCredentialTreatment($credentialTreatment); } } 

El siguiente método, de Zend_Auth_Adapter_DbTable, intenta autenticarse en una tabla, puede cambiarla para probar en tres tablas, y para cada una, cuando tenga éxito, configure esto como una bandera en la variable miembro privada. Algo como $ result [‘group1’] = 1; Configurará 1 para cada bash de inicio de sesión exitoso.

 /** * authenticate() - defined by Zend_Auth_Adapter_Interface. This method is called to * attempt an authentication. Previous to this call, this adapter would have already * been configured with all necessary information to successfully connect to a database * table and attempt to find a record matching the provided identity. * * @throws Zend_Auth_Adapter_Exception if answering the authentication query is impossible * @return Zend_Auth_Result */ public function authenticate() { $this->_authenticateSetup(); $dbSelect = $this->_authenticateCreateSelect(); $resultIdentities = $this->_authenticateQuerySelect($dbSelect); if ( ($authResult = $this->_authenticateValidateResultset($resultIdentities)) instanceof Zend_Auth_Result) { return $authResult; } $authResult = $this->_authenticateValidateResult(array_shift($resultIdentities)); return $authResult; } 

Devolverá un $ authresult válido solo si uno de los tres bashs de inicio de sesión se autenticó satisfactoriamente.

Ahora, en su controlador, después de intentar iniciar sesión:

 public function loginAction() { $form = new Admin_Form_Login(); if($this->getRequest()->isPost()) { $formData = $this->_request->getPost(); if($form->isValid($formData)) { $authAdapter = $this->getAuthAdapter(); $authAdapter->setIdentity($form->getValue('user')) ->setCredential($form->getValue('password')); $result = $authAdapter->authenticate(); if($result->isValid()) { $identity = $authAdapter->getResult(); Zend_Auth::getInstance()->getStorage()->write($identity); // redirect here } } } $this->view->form = $form; } private function getAuthAdapter() { $authAdapter = new MyAuthAdapter(Zend_Db_Table::getDefaultAdapter()); // Here the three tables $authAdapter->setTableName(array('users','users2','users3')) ->setIdentityColumn('user') ->setCredentialColumn('password') ->setCredentialTreatment('MD5(?)'); return $authAdapter; } 

La clave aquí es la siguiente línea, que se implementará en su adaptador de autenticación personalizado:

 $identity = $authAdapter->getResult(); 

Puede tomar como base este formulario Zend_Auth_Adapter_DbTable:

  /** * getResultRowObject() - Returns the result row as a stdClass object * * @param string|array $returnColumns * @param string|array $omitColumns * @return stdClass|boolean */ public function getResultRowObject($returnColumns = null, $omitColumns = null) { // ... } 

Esto devuelve la fila coincidente en el bash de inicio de sesión cuando se autentica correctamente. Entonces, creará su método getResult () que puede devolver esta fila y también los indicadores $ this-> result [‘groupX’]. Algo como:

 public function authenticate() { // Perform the query for table 1 here and if ok: $this->result = $row->toArrray(); // Here you can get the table result of just one table or even merge all in one array if necessary $this->result['group1'] = 1; // and so on... $this->result['group2'] = 1; // ... $this->result['group3'] = 1; // Else you will set all to 0 and return a fail result } public function getResult() { return $this->result; } 

Después de todo, puedes usar Zend_Acl para controlar tus vistas y otras acciones. Como tendrá los indicadores en Zend Auth Storage, puede usarlos como roles:

 $this->addRole(new Zend_Acl_Role($row['group1'])); 

Aquí hay algunos recursos:

http://framework.zend.com/manual/en/zend.auth.introduction.html

http://zendguru.wordpress.com/2008/11/06/zend-framework-auth-with-examples/

http://alex-tech-adventures.com/development/zend-framework/61-zendauth-and-zendform.html

http://alex-tech-adventures.com/development/zend-framework/62-allocation-resources-and-permissions-with-zendacl.html

http://alex-tech-adventures.com/development/zend-framework/68-zendregistry-and-authentication-improvement.html

Me inspiré en el Zym_Auth_Adapter_Chain , pero lo alteré ligeramente para que no se detenga en el primer adaptador que regresa con éxito.

 require_once 'Zend/Auth/Adapter/Interface.php'; require_once 'Zend/Auth/Result.php'; class My_Auth_Adapter_Chain implements Zend_Auth_Adapter_Interface { private $_adapters = array(); public function authenticate() { $adapters = $this->getAdapters(); $results = array(); $resultMessages = array(); foreach ($adapters as $adapter) { // Validate adapter if (!$adapter instanceof Zend_Auth_Adapter_Interface) { require_once 'Zend/Auth/Adapter/Exception.php'; throw new Zend_Auth_Adapter_Exception(sprintf( 'Adapter "%s" is not an instance of Zend_Auth_Adapter_Interface', get_class($adapter))); } $result = $adapter->authenticate(); if ($result->isValid()) { if ($adapter instanceof Zend_Auth_Adapter_DbTable) { $results[] = $adapter->getResultRowObject(); } else { $results[] = $result->getIdentity(); } } else { $resultMessages[] = $result->getMessages(); } } if (!empty($results)) { // At least one adapter succeeded, return SUCCESS return new Zend_Auth_Result(Zend_Auth_Result::SUCCESS, $results, $resultMessages); } return new Zend_Auth_Result(Zend_Auth_Result::FAILURE, null, $resultMessages); } public function getAdapters() { return $this->_adapters; } public function addAdapter(Zend_Auth_Adapter_Interface $adapter) { $this->_adapters[] = $adapter; return $this; } public function setAdapters(array $adapters) { $this->_adapters = $adapters; return $this; } } 

Para llamarlo desde un controlador, simplemente crea la cadena, luego los adaptadores que deseas usar (en tu caso, esto probablemente será un adaptador DB por tabla de entidad), y finalmente pasa los adaptadores a la cadena.

 $db = Zend_Db_Table::getDefaultAdapter(); // Setup adapters $dbAdminsAdapter = new Zend_Auth_Adapter_DbTable($db, 'admins'); $dbAdminsAdapter->setIdentityColumn('login') ->setCredentialColumn('password') ->setIdentity($login) ->setCredential($password); $dbUsersAdapter = new Zend_Auth_Adapter_DbTable($db, 'users'); $dbUsersAdapter->setIdentityColumn('login') ->setCredentialColumn('password') ->setIdentity($login) ->setCredential($password); ... // Setup chain $chain = new My_Auth_Adapter_Chain(); $chain->addAdapter($dbAdminsAdapter) ->addAdapter($dbUsersAdapter); // Do authentication $auth = Zend_Auth::getInstance(); $result = $auth->authenticate($chain); if ($result->isValid()) { // succesfully logged in } 

Este es solo el código de ejemplo básico, probablemente también quiera usar setCredentialTreatment en los adaptadores DbTable …

La ventaja de este enfoque es que será trivial agregar otros adaptadores existentes para otras formas de autenticación (es decir, OpenID) a la cadena más adelante …

Lo malo: como se obtendrá una matriz como resultado de cada llamada a Zend_Auth :: getInstance () -> getIdentity () ;. Por supuesto, puede cambiar esto en el adaptador de cadena, pero eso le queda a usted: p.

DESCARGO DE RESPONSABILIDAD : Realmente no creo que sea prudente hacerlo de esta manera. Para que funcione, debe compartir el mismo nombre de usuario y contraseña entre las diferentes tablas, de modo que si un usuario tiene más de 1 rol (identidad) cambia su contraseña, deberá asegurarse de que este cambio se propague a todas las tablas de identidad donde ese el usuario tiene una cuenta Pero dejaré de regañar ahora: p.

Como Zend_Auth es un singleton, la creación de adaptadores de autenticación personalizados para cada fuente de autenticación solo resuelve la primera mitad de este problema. La segunda mitad del problema es que desea poder iniciar sesión simultáneamente con varias cuentas: una de cada fuente de autenticación.

Hice una pregunta similar recientemente . La solución fue extender Zend_Auth como se muestra en la respuesta aceptada. Luego inicializo los diferentes tipos de autenticación en mi bootstrap.

 protected function _initAuth() { Zend_Registry::set('auth1', new My_Auth('auth1')); Zend_Registry::set('auth2', new My_Auth('auth2')); Zend_Registry::set('auth3', new My_Auth('auth3')); } 

Entonces, en lugar del singleton Zend_Auth::getInstance() usaría Zend_Registry::get('auth1') , etc.

¿Por qué no crear una vista que combine las 3 tablas y luego autenticar en esa vista?