Авторизация с использованием Zend_Auth


    В этой статье как обычно рассматривается использование одного из компонент зенд фреймворка, за исключением небольшого отклонения от плана: до этого момента в рубрике "Разработка приложения с помощью ZF" к каждой статье прикреплялся архив с исходным кодом демо-приложения, того что получалось в результате работы с компонентами - теперь так не будет, теперь будем рассматривать компоненты отдельно друг от друга, т.к. оказалось, что в рамках 2Developers это мало кому нужно. А по поводу Zend Framework CMS, мы начали открытый проект по её разработке с public SVN-ом и все такое, детали будут освещены позже, в следующих статьях.

    И так, авторизация с помощью Zend_Auth, функция "запомнить меня" и установка длительности сессии (времени залогиненности пользователя).

    Таблица пользователей в БД




CREATE TABLE `users` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `login` varchar(36) NOT NULL,
  `pass` varchar(36) NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `login` (`login`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;


    Контроллер


    Добавим 2 акшена в контроллер, например это будет UserController:


<?php
 
require_once 'Zend/Controller/Action.php';

class UserController extends Zend_Controller_Action
{    
    
    public function loginAction() 
    {
        // Если отправлены данные
        if(isset($_POST['login']) && !empty($_POST['login'])) {
        
            // Подключиться к базе и получить адаптер
            require_once 'Zend/Db.php';
            $db_adapter = Zend_Db::factory('pdo_mysql',
                    array('host'     => 'localhost',
                          'username' => 'test',
                          'password' => 'test',
                          'dbname'   => 'test'
                    )
            );
            
            // Получить модель
            require_once(APPPATH."/models/User.php");
            $user_model = new User($db_adapter);
            
            if (true === $message = $user_model->login($_POST['login'], $_POST['pass'])) {
            // Успешно
                $this->_redirect('/');
            } else {
                $this->view->assign('errors', $message);
            }

        }
    }
    //__________________________________________________________
    
    public function logoutAction()
    {
        // отключение скрипта вида и layout'a
        $this->_helper->viewRenderer->setNoRender(true);
        Zend_Layout::getMvcInstance()->disableLayout();
        
        require_once 'Zend/Auth.php';
        $auth = Zend_Auth::getInstance();
        // Удалить из сессии информацию
        $auth->clearIdentity();
        Zend_Session::forgetMe();
        $this->_redirect('/');
    }
    //__________________________________________________________

    Как вы могли заметить, основное действие и работа с компонентом Zend_Auth происходит в модели. Здесь только получем результат, если успешно, тогда модель вернет true, в противном случае сообщение об ошибке.

    Модель



<?php
 
require_once 'Zend/Db/Table/Abstract.php';

class User extends Zend_Db_Table_Abstract
{
    protected $_name = 'users';    
    protected $_primary = array('login');
    
    public function login($login, $pass)
    {
        require_once 'Zend/Auth.php';
        // Получить экземпляр Zend_Auth
        $auth = Zend_Auth::getInstance();
        
        require_once 'Zend/Auth/Adapter/DbTable.php';
    
        // Создаем Adapter для Zend_Auth, указывая ему где в БД искать логин и пароль для сравнения
        $authAdapter = new Zend_Auth_Adapter_DbTable($this->getAdapter(), 'users', 'login', 'pass', "MD5(?)");

        $authAdapter->setIdentity($login)
                    ->setCredential($pass);

        // Проверяет и сохраняет результат проверки
        $result = $auth->authenticate($authAdapter);
        
        if ($result->isValid()) {
        // Успешно

            // Можно записать в сессию некоторые поля
            $auth->getStorage()->write($authAdapter->getResultRowObject(array('id', 'login')));

            // Получить объект Zend_Session_Namespace
            require_once('Zend/Session/Namespace.php');
            $session = new Zend_Session_Namespace('Zend_Auth');
            // Установить время действия залогинености
            $session->setExpirationSeconds(24*3600);
            
            // если отметили "запомнить"
            if (isset($_POST['rememberme'])) {
                Zend_Session::rememberMe();
            }
            return true;
        }
        
        // Неудачно
        return $error_msg = $result->getMessages();
    }
}

    Здесь есть несколько моментов, не описаных в мануале ZF, на которые следует обратить внимание.
    Во-первых использование четвертого параметра при получении Auth адаптера - функция, которая применяется к паролю. Можно дбавить salt, а можно вообще хранить его в открытом виде и не передавать этот параметр, но вы наверняка так не поступите ;).
    Второе это время жизни сессии часто необходимо что бы было больше, чем кажется 15 минут по умолчанию.
    Третья "запомнить меня", сохраняет куки в браузере клиента.
   

    Скрипт вида




<form action="<?php echo $this->url(); ?>" method="post">
<fieldset>
<legend>Вход</legend>
    
<?php if (sizeof($this->errors)) echo $this->formErrors($this->errors).'<br />'; //Вывод ошибок маркированным списком ?>

    <label for="login">Логин</label>
    <input type="text" id="login" name="login" value="<?php if (isset($_POST['login'])) echo $_POST['login'];?>" />
    <br /><br />
    
    <label for="pass">Пароль</label>
    <input type="password" id="pass" name="pass" value="<?php if (isset($_POST['pass']))  echo $_POST['pass'];?>" />
    <br /><br />
    
    <label for="rememberme">Запомнить меня</label>
    <input type="checkbox" id="rememberme" name="rememberme" value="1" />
    <br /><br />

    <input type="submit" value="Войти" />
    <br /><br />

</fieldset>
</form>

    Кажется это и все, для базового использования.



Добавлена: 13-03-2009 | Изменена: 23-03-2009 | Пользователем: djaarf | Просмотров: 4772

Комментарии

lcf 17-03-2009 13:18

Чтобы сделать редирект отключать лэйаут и скрипт вида вовсе не нужно. До них дело не дойдет всё равно.

С точки зрения ООП и ухода от суперглобальных массивов вместо $_POST и всяких isset надо пользоваться методами объекта запроса. Например

$request = $this->getRequest(); // в контроллере получили объект запроса

if ($request->isPost()) { // так можно проверить был ли это пост запрос

$post = $request->getPost()  // - так можно все данные взять что в пост запросе пришли

$itemsPerPage = $request->getPost('itemsPerPage'); // так можно получить какую то переменную, причем если её нет, то вернется null

Ну и контроллеры конеш толстоваты, но в рамках учебного материала это не так важно.

Хорошее описание для базового понимания.

djaarf 17-03-2009 14:56
По поводу объекта запроса, интересное замечание спасибо, ну а насчет толстоватости контроллера, если подключение к базе убрать, что там останется? Конечно же это для наглядности.

HighAley 04-04-2009 20:50
 В данном примере не мешало бы использовать Zend_Form.
djaarf 05-04-2009 00:44
HighAley, я например, наоборот стараюсь воздержаться от использования Zend_Form особенно при создании сайтов, я еще не знаю такого дизайнера, который разобрался с декораторами и тому подобным. Понятно, если система электронного документооборота или какая нибудь админка сложная, Zend_Form может быть необходимым, но форма авторизации... она ведь одна такая на все приложение, мне кажется это слишком, особенно если вспомнить основную причину для применения Zend_Form.
mojojojo 29-04-2009 17:59
Зехр гут! Особенно про римемберМи
Romiz 10-05-2009 03:05
У меня вопрос по поводу  Zend_Session::rememberMe() - этот метод устанавливает время жизни +2 недели для куки PHPSESSID, т.е. для идентификатора сессии, которая умрет через 24*3600, т.е. через сутки.
Как же тогда сработает авторизация через пару дней?!
На самом деле, помимо
PHPSESSID я ожидал увидеть в куках какой-нить хеш или сериализованный массив с информацией о пользователе.

В чем я заблуждаюсь?!
djaarf 16-05-2009 00:03
А ведь точно, вы ни в чем не заблуждаетесь, я упустил. Действительно ведь и на этом сайте не запоминает более, чем на сутки т.к. сделано так же. А я не замечал.

Значит нужно сделать проверку на то установлен ли параметр "запомнить" при логине,
и исходя из этого уже устанавливать время жизни сессии на сервере.

Если "запоминать" не нужно, то оставить как сейчас, к примеру сутки, а если нужно запомнить, то установить время жизни 24*3600*14.

Спасибо, что отметили этот недочет. Странно в мануале ZF никак не упоминается эта зависимость.
Romiz 16-05-2009 00:41
Тут есть ещё один неприятный для меня момент - это хранении самой сессии такое большое кол-во времени. Например, возможен вариант, что хостер не даст редактировать связанные с этим настройки в php.ini и т.д. и т.п.
Выходом конечно может быть хранение сессий в таблице БД.

Вообще, для реализации "remember me" , мне самому больше нравится вариант с сохранением зашифрованной инфы в куках, ключ к которой вшит где-нибудь в конфигах приложения :)




Оставить комментарий



Капча *

Captcha

Комментарий будет опубликован после проверки модератором

Для подсветки синтаксиса исходный код следует обрамлять следующими тэгами
<pre><code class="синтаксис" >код</code></pre>
Подерживаются следующие: cpp php javascript sql html-xml css ini