Pre-Post диспетчеризация, авторизация и Zend_Controller_Plugin_ErrorHandler


Хороший подводный камень затаился в механизме работы ZF с плагинами когда вопрос авторизации разрешается именно с их помощью.

Вводная

Общеизвестно, что кроме прочего плагины позволяют выполнять некий код до и после действия (action) контроллера. Именно тут и притаилась логическая бомба размеров чуть меньше среднего.

Обычно авторизация (определение возможности выполнения тех или иных деяний в зависимости от прав) помещается в Pre-обработчик:

class Application_Controller_Plugin_Auth extends Zend_Controller_Plugin_Abstract{
    public function preDispatch(Zend_Controller_Request_Abstract $request){
        /*
        ...
        */
    }
}
о выборе:

конечно, можно было бы поместить проверку в обработчик dispatchLoopStartup, но если в ходе выполнения запроса будут вызываться несколько контроллеров и действий, то авторизация будет неполной

Код preDispatch представляет собой проверку возможности выполнения запрашиваемого действия с вынесением вердикта в виде перезаписи значений модуля, контроллера и действия. В случае когда перезапись нужно произвести как в случае отказа, так и благоприятного исхода и возникает неловкость.

Плагин Zend_Controller_Plugin_ErrorHandler, включенный по-умолчанию, регистрирует Post-обработчик и выполняет аналогичные действия с перезаписью значений модуля, контроллера и действия, но в случае возникновения исключений.

об исключениях:

обычно в задачу этому плагину ставится отлов отсутствия вызываемого контроллера или действия, что можно рассматривать как ошибку №404, в то время как исключения внутри существующих действий как ошибку №500

Суть

Авторизация, в подавляющем большинстве конфигураций, пропустит нас к несуществующему действию. Однако обработчик ошибок чутко перенаправит на контроллер и действие (по-умолчанию error и error соответственно) по обработке ошибки, что в цикле диспетчеризации опять вызовет проверку авторизации. Если забыть прописать правила на доступ к контроллеру и действию обработки ошибок, мы будем повторно брошены на поиски несуществующего со всеми печальными последствиями: плагин ErrorHandler, почуяв мистический вызов себя второй раз, бросит неотлавливаемое уже никем (ясное дело, их отловом он и занимается) исключение и все будет потеряно.

к слову о перестраховке:

можно обернуть в try…catch вызов Zend_Controller_Front::getInstance()->dispatch() чтобы ловить неотлавливаемое и там

Вывод и возможные решения

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

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

public function preDispatch(Zend_Controller_Request_Abstract $request){
    if ($this->_response->isException()) return;
    /*
    ...
    */
}

5 отзывов на «Pre-Post диспетчеризация, авторизация и Zend_Controller_Plugin_ErrorHandler»

  1. Николай,

    А зачем _обязательно_ переписывать при авторизации значения контроллера и так далее?

  2. wd,

    Ну, к примеру, если юзер, зарегистрирован, но потерял некое право (платный период закончился) что-либо делать в полной мере. Т.е. он по сути получает один и тот же ресурс (в терминах ACL), но под другой ролью. Но в целом вопрос правомерен, конечно - очень ограничивающее условие. Тут дело, скорее, в том, что следует следить и знать про возможность где-либо перезаписывать координаты модуль-контроллер-действие уже после того как приложение навострилось на обработку ошибок.

  3. Дмитрий,

    Есть ли эксепшены лучше проверять не getException(), а isException().

  4. wd,

    Верно, да, спасибо. Смотрел содержимое коллекции исключений и скопипастил :\. А так, Вы, разумеется, правы.

  5. illusive,

    Хорошая заметка. Надо быть повнимательнее….

Оставить отзыв

 

Май 2008
Пн Вт Ср Чт Пт Сб Вс
« Апр   Июнь »
 1234
567891011
12131415161718
19202122232425
262728293031