Zend_Auth: разрешить пользователю входить в несколько таблиц / идентификаторов - PullRequest
9 голосов
/ 02 августа 2010

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

Запрашивается обычная таблица mySQL "users" со столбцами 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.

Ответы [ 4 ]

10 голосов
/ 04 августа 2010

Вы должны создать свой собственный 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 /разработка / Зенд-основа / 68-zendregistry-и-аутентификации improvement.html

3 голосов
/ 09 августа 2010

Я черпал вдохновение из 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
}

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

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

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

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

2 голосов
/ 01 декабря 2010

Поскольку Zend_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'));
}

Таким образом, вместо синглтона Zend_Auth::getInstance() вы бы использовали Zend_Registry::get('auth1') и т. Д.

1 голос
/ 06 августа 2010

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

...