Zend_Auth: Allow user to be logged in to multiple tables/identities

前端 未结 4 1524
时光说笑
时光说笑 2021-02-06 02:23

I am using Zend_Auth for authentication in a web portal.

A normal mySQL \"users\" table with a login and password column gets quer

4条回答
  •  离开以前
    2021-02-06 03:10

    I took some inspiration from the Zym_Auth_Adapter_Chain, but altered it slightly so it doesn't stop on the first adapter that returns successfully.

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

    To call it from a controller you simply create the chain, then the adapters you want to use (in your case this will probably be a DB adapter per entity table), and finally pass the adapters to the chain.

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

    This is just basic example code, you probably want to use setCredentialTreatment also on the DbTable adapters...

    The upside of this approach is that it will be trivial to add other existing adapters for other forms of authentication (ie. OpenID) to the chain later on...

    The downside : as is you will get an array as result from every call to Zend_Auth::getInstance()->getIdentity();. You could of course change this in the Chain adapter, but that's left to you :p.

    DISCLAIMER : I really don't think it's wise to do it this way. To make it work you have to share the same login and password accross the different tables, so if a user has more then 1 role (identity) changes his password you'll have to make sure this change is propagated to all identity tables where that user has an account. But I'll stop nagging now :p.

提交回复
热议问题