Zend_Auth: Позвольте пользователю быть зарегистрированным к нескольким таблицам/идентификационным данным

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

Нормальная "пользовательская" таблица MySQL с a 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!

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

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

Я - относительный новичок к Платформе Зенда.

9
задан Pekka supports GoFundMonica 4 August 2010 в 16:50
поделиться

3 ответа

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

1
ответ дан 4 December 2019 в 12:58
поделиться

Вы должны создать свой собственный Zend_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, пытается аутентифицироваться по одной таблице, вы можете изменить его, чтобы попробовать в трех таблицах, и для каждой, когда вы добьетесь успеха, вы установите это как флаг в частной переменной-члене. Что-то вроде $ 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

10
ответ дан 4 December 2019 в 12:58
поделиться

Я немного вдохновился 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
}

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

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

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

DISCLAIMER : Я действительно не думаю, что это разумно делать таким образом. Чтобы это работало, вы должны использовать один и тот же логин и пароль в разных таблицах, поэтому если пользователь с более чем одной ролью (identity) изменит свой пароль, вам придется убедиться, что это изменение будет распространено на все таблицы identity, в которых у этого пользователя есть учетная запись. Но теперь я перестану придираться :p.

3
ответ дан 4 December 2019 в 12:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: