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

前端 未结 4 1528
时光说笑
时光说笑 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:08

    You should create your own Zend_Auth_Adapter. This adapter will try to authenticate against your three resources and will flag it in a private member variable, so you can know which of the logins attempts were sucefully authenticated.

    To create your Auth Adapter you can take as basis the Zend_Auth_Adapter_DbTable.

    So, in the __construct instead of pass just one DbTable adapter, you can pass the three adapters used in each resource. You'll do in that way only if each one use different resources, like LDAP for example, or even another database, if not, you can pass just one adapter and set three different table names in the configuration options.

    Here is the example from 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);
            }
        }
    

    The method bellow, from Zend_Auth_Adapter_DbTable, try to authenticate against one table, you can change it to try in three tables, and for each, when you get sucess, you set this as a flag in the private member variable. Something like $result['group1'] = 1; You'll set 1 for each sucessfully login attempt.

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

    You will return a valid $authresult only if one of the three login attempts were sucessfully authenticated.

    Now, in your controller, after you try to login:

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

    The key here is the line bellow, that will be implemeted in your custom auth adapter:

    $identity = $authAdapter->getResult();
    

    You can take as basis this form 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)
        {
            // ...
        }
    

    This return the row matched in the login attempt when sucessfully authenticated. So, you'll create your getResult() method that can return this row and also the $this->result['groupX'] flags. Something like:

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

    After all you can use Zend_Acl to take control over your views and other actions. Since you will have the flags in the Zend Auth Storage, you can use than as roles:

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

    Here is some resources:

    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

提交回复
热议问题