Zend_Auth: разрешить пользователю вход в несколько таблиц / идентификаторов

Я использую Zend_Auth для аутентификации на веб-портале.

Обычная таблица пользователей «mySQL» с столбцом login и password запрашивается, и пользователь вошел в систему.

Тем не менее, у меня есть две дополнительные группы пользователей, которые я хочу аутентифицировать. Все три группы пользователей имеют свои данные входа в другие таблицы . Их данные поступают из внешних источников, поэтому объединение этих учетных записей в один из них нежелательно.

Таким образом, может быть, что пользователь является аутентифицированным пользователем из любой из трех групп, даже всех трех из них, в то же время .

Каждая из трех групп входа имеет свою собственную форму входа и выход из системы.

На данный момент у меня есть единственный, простой логин Zend_Auth , взятый из некоторого учебника и слегка измененный, который выглядит примерно так:

 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! 

где я должен начать, чтобы это послужило и адресовало отдельные «зарегистрированные» состояния для трех групп? Моя идея состоит в том, что я хотел бы поделиться сеансом и управлять аутентификацией отдельно.

Это возможно? Может быть, есть простой префикс, который делает это проще? Существуют ли какие-либо учебники или ресурсы по этой проблеме?

Я относительный новичок в Zend Framework.

Вы должны создать свой собственный Zend_Auth_Adapter. Этот адаптер попытается аутентифицировать ваши три ресурса и будет отмечать его в частной переменной-члене, поэтому вы можете узнать, какие попытки входа были успешно завершены.

Чтобы создать свой Auth Adapter, вы можете взять за основу Zend_Auth_Adapter_DbTable.

Таким образом, в __construct вместо передачи только одного адаптера DbTable вы можете передать три адаптера, используемые в каждом ресурсе. Вы будете делать это только в том случае, если каждый из них использует разные ресурсы, например, LDAP или даже другую базу данных, если нет, вы можете передать только один адаптер и установить три разных имени таблицы в параметрах конфигурации.

Вот пример из 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); } } 

Метод ниже, из Zend_Auth_Adapter_DbTable, попытается выполнить проверку подлинности в отношении одной таблицы, вы можете изменить его, чтобы попробовать в трех таблицах, и для каждого, когда вы получите sucess, вы установите его как флаг в переменной частного члена. Что-то вроде $ result ['group1'] = 1; Вы будете устанавливать 1 для каждой успешной попытки входа в систему.

 /** * 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; } 

Вы вернете действительный $ authresult только в том случае, если одна из трех попыток входа была успешно завершена.

Теперь, в вашем контроллере, после попытки входа в систему:

 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; } 

Ключевым моментом здесь является строка ниже, которая будет реализована в пользовательском адаптере аутентификации:

 $identity = $authAdapter->getResult(); 

Вы можете принять за основу эту форму 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) { // ... } 

Это возвращает строку, сопоставленную при попытке входа в систему при успешной аутентификации. Таким образом, вы создадите свой метод getResult (), который может вернуть эту строку, а также флаги $ this-> result ['groupX']. Что-то вроде:

 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; } 

В конце концов вы можете использовать Zend_Acl для контроля над своими представлениями и другими действиями. Поскольку у вас будут флаги в Zend Auth Storage, вы можете использовать их, а не как роли:

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

Вот некоторые ресурсы:

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

Я немного вдохнул Zym_Auth_Adapter_Chain , но немного изменил его, чтобы он не останавливался на первом адаптере, который успешно возвращается.

 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; } } 

Чтобы вызвать его из контроллера, вы просто создаете цепочку, а затем адаптеры, которые вы хотите использовать (в вашем случае это, вероятно, будет адаптером базы данных для каждой таблицы сущностей) и, наконец, передайте адаптеры в цепочку.

 $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 } в $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 } в $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 } 

Это всего лишь базовый пример кода, вероятно, вы хотите использовать setCredentialTreatment также для адаптеров DbTable …

Поверхность этого подхода заключается в том, что будет тривиально добавлять другие существующие адаптеры для других форм аутентификации (то есть OpenID) в цепочку позже …

Недостаток: как вы получите массив в результате каждого вызова в Zend_Auth :: getInstance () -> getIdentity () ;. Разумеется, вы можете изменить это в адаптере Chain, но это вам осталось: p.

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ : Я действительно не думаю, что разумно делать это таким образом. Чтобы заставить его работать, вы должны использовать один и тот же логин и пароль в разных таблицах, поэтому, если у пользователя более 1 роль (идентификатор) изменяется его пароль, вам нужно убедиться, что это изменение распространяется на все таблицы идентификации, где это у пользователя есть учетная запись. Но я перестану ныть сейчас: p.

Поскольку Zend_Auth является одноэлементным, создание пользовательских адаптеров auth для каждого источника аутентификации разрешает только первую половину этой проблемы. Вторая половина проблемы заключается в том, что вы хотите иметь возможность входа одновременно с несколькими учетными записями: один из каждого источника аутентификации.

Недавно я задал аналогичный вопрос . Решение состояло в том, чтобы расширить Zend_Auth, как показано в принятом ответе. Затем я инициализирую различные типы аутентификации в своем бутстрапе.

 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')); } 

Итак, вместо singleton Zend_Auth::getInstance() вы должны использовать Zend_Registry::get('auth1') и т. Д.

Почему бы просто не создать представление, которое объединило бы все 3 таблицы, а затем аутентифицировало бы против этого представления?