Рекомендации Zend_Auth

Моя цель - требовать авторизации на определенных страницах. Я использую Zend Framework MVC и пытаюсь найти примеры лучших практик.

Некоторые заметки о том, что я ищу:

  • Я хочу, чтобы пользователи, не вошедшие в систему, получили поле входа в систему, а затем вернулись к версии страницы, вошедшей в систему, после аутентификации
  • Я хочу использовать инъекцию зависимостей и избегать синглтонов
  • Небольшой размер кода - привязка к структуре MVC Zend
  • Должен ли блок входа быть отдельным контроллером и выполнять перенаправление заголовка? Как вернуться на целевую страницу после успешной аутентификации? Идея просто вызвать действие контроллера входа в систему, чтобы отобразить поле входа на целевой странице, или это недостаток в отношении индексации поисковой системы?
  • Уметь использовать внешнюю библиотеку для обработки файлов cookie.

Или что-то совсем другое. Я новичок в среде Zend и хочу делать это «правильно».


person Jon Skarpeteig    schedule 01.04.2011    source источник


Ответы (3)


  • Я хочу, чтобы пользователи, не вошедшие в систему, получили поле входа в систему, а затем вернулись к версии страницы, вошедшей в систему, после аутентификации

Используйте плагин FrontController и перенаправляйте их на свой loginAction. .

  • Я хочу использовать инъекцию зависимостей и избегать синглтонов

Zend Framework в настоящее время не поставляет никакой системы DI, однако Zend_Application_Resource_ * фактически заменяет ее. Какая зависимость вам здесь нужна?

  • Небольшой размер кода - привязка к структуре MVC Zend

Решать вам.

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

Я в основном использую специальный AuthController с LoginAction & LogoutAction. Чтобы перенаправить пользователя на страницу, которую пытается просмотреть, я всегда добавляю элемент returnUrl в свои формы и вводю значение запрошенного URL-адреса, чтобы иметь возможность перенаправить пользователя, и если его нет, я перенаправляю его в индекс / приборная панель, зависит.

  • Уметь использовать внешнюю библиотеку для обработки файлов cookie.

Zend_Auth позволяет вам установить свой собственный механизм хранения, так что просто реализуйте интерфейс.

$auth = Zend_Auth::getInstance();
$auth->setStorage(new My_Auth_Storage());

Но никогда не сохранять результат аутентификации в файле cookie, его очень легко изменить и получить доступ к своему веб-сайту.

Вы также можете ознакомиться с одним из моих предыдущего ответа.

person Boris Guéry    schedule 01.04.2011
comment
Что касается необходимой зависимости - в частности, обработчика хранилища сеансов. Что касается аутентификации cookie - я реализовал принципы дизайна из jaspan.com/improved_persistent_login_cookie_best_practice и хочу использовать это. - person Jon Skarpeteig; 01.04.2011
comment
Если вы действительно хотите использовать DI, вы можете использовать Symfony DI, который можно хорошо интегрировать в ZF blog.starreveld.com/2009/11/ Однако это может вызвать дополнительные расходы, если вы планируете использовать его только для Auth. Вы по-прежнему можете написать AuthService и получить его с помощью ресурса приложения $ this- ›getInvokeArg ('boostrap') -› getResource ('AuthService'); или используя Zend_Registry. - person Boris Guéry; 01.04.2011
comment
Как заполнить returnUrl на https-страницах без реферера? - person Jon Skarpeteig; 04.04.2011
comment
Вы можете добавить параметр GET в свой плагин Auth Front Controller и перенаправить на свой Auth Controller, или вы можете настроить его в $ _SESSION, но многооткрытая вкладка может привести к непоследовательному результату - person Boris Guéry; 04.04.2011

Вы можете использовать комбинацию Zend_Auth и Zend_Acl. Чтобы расширить другие ответы, я приведу краткий пример того, как вы можете управлять аутентификацией с помощью zend framework:

Сначала вам нужно настроить плагин для предварительной отправки всех запросов и проверить, разрешен ли клиенту доступ к определенным данным. Этот плагин может выглядеть так:

class Plugin_AccessCheck extends Zend_Controller_Plugin_Abstract {

    private $_acl = null;

    public function __construct(Zend_Acl $acl) {
        $this->_acl = $acl;
    }

    public function preDispatch(Zend_Controller_Request_Abstract $request) {
        //get request information
        $module = $request->getModuleName ();
        $resource = $request->getControllerName ();
        $action = $request->getActionName ();

        try {
            if(!$this->_acl->isAllowed(Zend_Registry::get('role'), 
                                $module . ':' . $resource, $action)){
                $request->setControllerName ('authentication')
                        ->setActionName ('login');
            }
        }catch(Zend_Acl_Exception $e) {
            $request->setControllerName('index')->setActionName ('uups');
        }
    }
}

Таким образом, каждый тип пользователя имеет определенные разрешения, которые вы определяете в своей библиотеке acl. При каждом запросе вы проверяете, разрешен ли пользователю доступ к ресурсу. Если вы не перенаправляете на страницу входа, иначе preDispatch передает пользователя на ресурс.

В Zend_Acl вы определяете роли, ресурсы и разрешения, которые разрешают или запрещают доступ, например:

class Model_LibraryAcl extends Zend_Acl {
    public function __construct() {

        $this->addRole(new Zend_Acl_Role('guests'));
        $this->addRole(new Zend_Acl_Role('users'), 'guests');
        $this->addRole(new Zend_Acl_Role('admins'), 'users');                

        $this->add(new Zend_Acl_Resource('default'))
             ->add(new Zend_Acl_Resource('default:authentication'), 'default')
             ->add(new Zend_Acl_Resource('default:index'), 'default')
             ->add(new Zend_Acl_Resource('default:error'), 'default');

        $this->allow('guests', 'default:authentication', array('login'));
        $this->allow('guests', 'default:error', 'error');

        $this->allow('users', 'default:authentication', 'logout');          
    }
}

Затем вам нужно настроить acl и auth в файле начальной загрузки:

    private $_acl = null;

    protected function _initAutoload() {

       //...your code           
       if (Zend_Auth::getInstance()->hasIdentity()){
        Zend_Registry::set ('role',
                     Zend_Auth::getInstance()->getStorage()
                                              ->read()
                                              ->role);
        }else{
            Zend_Registry::set('role', 'guests');
        }

        $this->_acl = new Model_LibraryAcl ();
        $fc = Zend_Controller_Front::getInstance ();
        $fc->registerPlugin ( new Plugin_AccessCheck ( $this->_acl ) );

        return $modelLoader;
    }

Наконец, в вашем контроллере аутентификации вы должны использовать настраиваемый адаптер аутентификации и настроить действия для входа и выхода:

public function logoutAction() {
    Zend_Auth::getInstance ()->clearIdentity ();
    $this->_redirect ( 'index/index' );
}

private function getAuthAdapter() {
    $authAdapter = new Zend_Auth_Adapter_DbTable ( 
                        Zend_Db_Table::getDefaultAdapter ());
    $authAdapter->setTableName('users')
                ->setIdentityColumn('email')
                ->setCredentialColumn ('password')
                ->setCredentialTreatment ('SHA1(CONCAT(?,salt))');

    return $authAdapter;
}

В вашем действии входа в систему вам необходимо передать данные входа в адаптер аутентификации, который выполняет аутентификацию.

$authAdapter = $this->getAuthAdapter ();
$authAdapter->setIdentity ( $username )->setCredential ( $password );
$auth = Zend_Auth::getInstance ();
$result = $auth->authenticate ( $authAdapter );

if ($result->isValid ()) {
    $identity = $authAdapter->getResultRowObject ();
    if ($identity->approved == 'true') {
        $authStorage = $auth->getStorage ();
        $authStorage->write ( $identity );
        $this->_redirect ( 'index/index' );
    } else {
       $this->_redirect ( 'authentication/login' );
  }

И это все. Я рекомендую вам это КАК на YouTube на zend auth и zend acl.

person Upvote    schedule 02.04.2011
comment
Это самый полный ответ, который я когда-либо видел на SO! +1 За это! - person Frederick Marcoux; 28.11.2012

Не уверен, что это лучшая практика, но если бы я реализовал то, что вам нужно, я бы сделал следующее:

  1. Создайте LoginForm с однозначно идентифицируемой кнопкой отправки (объяснено позже)
  2. Создайте AuthService с помощью методов getLoginForm, login, logout и одного или всех из: getIdentity, hasIdentity и аналогичных методов.
  3. Создайте средство просмотра, у которого есть экземпляр этой службы, и, в зависимости от результата hasIdentity, либо визуализируйте LoginForm, либо визуализируйте личность вошедшего в систему пользователя в представлениях, которым нужна эта функциональность.
  4. Создайте плагин фронт-контроллера, который также имеет экземпляр службы и реализует ловушку плагина preDispatch. Дайте ему некоторую конфигурацию того, какие действия нужно исследовать. Если AuthService->hasIdentity() вернет истину, ничего не делать. Если запрос является почтовым запросом, ищите однозначно идентифицируемое имя кнопки отправки, то есть: $request->getPost( 'loginSubmitButton', null ); по умолчанию null, если он недоступен. Если не null, сделайте login( $request->getPost() ) на сервисе. В случае успеха перенаправьте на то же действие, в случае неудачи - и снова отобразите форму в помощнике просмотра (автоматически отображая ошибки).

Служба может быть получена как средством просмотра, так и подключаемым модулем фронт-контроллера, при этом некоторый локатор службы может выполнять что-то вроде ServiceAbstract::getService( 'Auth' ), регистрируя службу в ServiceAbstract в загрузочном файле.

person Decent Dabbler    schedule 01.04.2011