代码之家  ›  专栏  ›  技术社区  ›  Pekka

Zend_Auth:允许用户登录到多个表/标识

  •  9
  • Pekka  · 技术社区  · 16 年前

    我在用 Zend_Auth

    一个普通的mySQL“users”表 login password 列被查询,用户登录。

    其他表中的登录数据 . 它们的数据来自外部来源,因此不希望将这些登录帐户统一到一个帐户中。

    同时 .

    三个登录组中的每一个都有自己的登录表单和注销按钮。

    目前,我只有一个,直截了当的 登录,从一些教程和稍微修改,看起来像这样:

    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框架的新手。

    4 回复  |  直到 16 年前
        1
  •  10
  •   Keyne Viana    16 年前

    您应该创建自己的Zend_Auth_适配器。此适配器将尝试对您的三个资源进行身份验证,并将其标记在私有成员变量中,以便您可以知道哪些登录尝试已成功进行身份验证。

    要创建身份验证适配器,可以将Zend_Auth_Adapter_DbTable作为基础。

    因此,在\uu构造中,您可以传递每个资源中使用的三个适配器,而不是只传递一个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,尝试对一个表进行身份验证,您可以将其更改为在三个表中进行尝试,对于每个表,当您获得成功时,将其设置为private member变量中的标志。类似于$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存储中有这些标志,因此可以将than用作角色:

    $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

        2
  •  3
  •   wimvds    16 年前

    我从 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适配器),最后将适配器传递到链。

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

    这只是基本的示例代码,您可能还想在DbTable适配器上使用setCredentialTreatment。。。

    这种方法的好处是,稍后将其他现有的适配器(例如,OpenID)添加到链中,这将是微不足道的。

    缺点:按原样,每次调用Zend_Auth::getInstance()->getIdentity();都会得到一个数组;。当然,您可以在链适配器中更改此项,但这留给您:p。

    :我真的不认为这样做是明智的。要使其工作,您必须在不同的表中共享相同的登录名和密码帐户,因此,如果一个用户有多个角色(标识)更改了他的密码,则必须确保将此更改传播到该用户有帐户的所有标识表中。但我现在不唠叨了:p。

        3
  •  2
  •   Community Mohan Dere    9 年前

    因为Zend_Auth是单例的,所以为每个身份验证源创建自定义身份验证适配器只能解决这个问题的前半部分。问题的后半部分是您希望能够同时使用多个帐户登录:每个身份验证源一个。

    similar question recently . 解决方案是扩展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'));
    }
    

    所以,不是单身汉 Zend_Auth::getInstance() 你会用 Zend_Registry::get('auth1')

        4
  •  1
  •   iWantSimpleLife    16 年前

    为什么不创建一个合并所有3个表的视图,然后根据该视图进行身份验证?