Это перевод второй части статьи с DevZone об использовании Zend_Acl MVC Zend Framework.
В первой части мы говорили о том, как настроить экземпляр Zend_Acl, и как присоединить его к окружению MVC (с использованием плагина фронт-контроллера). Но как насчет установки другого действия для обработки запрета доступа, или как сделать, чтобы статью мог редактировать только ее владелец? Это и кое-то другое вы найдете в приведенных ниже примерах.
Как я упоминал в первой части, эта статья основана на Предложениях Zend Framework (ссылка), которая в настоящее время находится в лаборатории (Лаборатория – часть кода и концепции Zend Framework, которая внесена в проект, но дожидается утверждения для внесения в основной релиз, – прим. переводчика).
1. Использование модулей
Давайте поговорим об использовании модулей. Мы использовали в качестве примера для данной статьи сайт аналогичный devzone. Как насчет того, чтобы создать административный модуль, для утверждения (одобрения) статей и некоторых других задач (например, измениения быстрых ссылок или разделов)? Для этого нам потребуется изменить модель ресурсов нашего ACL:
Модуль по-умолчанию:
- Контроллер user.
- Контроллер article.
Административный модуль:
- Контроллер article.
- Контроллер quick-link.
- Контроллер category.
Основываясь на данной модели ресурсов, создадим экземпляр Zend_Acl, отображающий это.
ВАЖНО
Помните, этот код и создание объекта Zend_Acl должны быть выполнены до вызова метода диспетчеризации фронт-контроллера (в файле bootstrap).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | /** Создание Ролей */ require_once 'Zend/Acl/Role.php'; $myAcl->addRole(new Zend_Acl_Role('guest')) ->addRole(new Zend_Acl_Role('writer'), 'guest') ->addRole(new Zend_Acl_Role('admin'), 'writer'); /** Создание Ресурсов */ require_once 'Zend/Acl/Resource.php'; /** Модуль по-умолчанию */ $myAcl->add(new Zend_Acl_Resource('user')) ->add(new Zend_Acl_Resource('article')); /** Административный модуль */ $myAcl->add(new Zend_Acl_Resource('admin')) ->add(new Zend_Acl_Resource('admin:article', 'admin')) ->add(new Zend_Acl_Resource('admin:quick-link', 'admin')) ->add(new Zend_Acl_Resource('admin:category', 'admin')); /** Создание привелегий */ $myAcl->allow('guest', 'user') ->deny('guest', 'article') ->allow('guest', 'article', 'view') ->allow(array('writer', 'admin'), 'article', array('add', 'edit')) ->allow('admin', 'admin'); /** Установка фронт-контроллера */ require_once 'Zend/Controller/Front.php'; $front = Zend_Controller_Front::getInstance(); $front->setControllerDirectory(array('default' => 'path/to/default/controllers', 'admin' => 'path/to/admin/controllers')); /** Регистрация объекта плагина */ require_once 'Zend/Controller/Plugin/Acl.php'; $front->registerPlugin(new Zend_Controller_Plugin_Acl($myAcl, 'guest')); /** Запуск диспетчеризации */ $front->dispatch(); |
Заметьте, мы создали ресурс для каждого контроллера модуля по-умолчанию, а для административного модуля – ресурс для самого модуля и по одному для каждого контроллера внутри модуля (в формате ‘модуль:контроллер’), которые являются дочерними по отношению к ресурсу модуля администрирования. Кроме того мы указали, что только пользователи с административной ролью имеют доступ к административному модулю.
2. Использование ролей
Войдя в приложение, пользователь должен получить одну из ролей (в нашем примере роль может быть ‘guest, ‘writer’ или ‘admin’). Так как же мы можем определить роль в наших приложениях? Для начала необходимо сохранить роль в переменной, которая хранится в сессии. Поэтому, после авторизации пользователя, нужно сохранить его роль в хранилище сессии, а при последующих запросах, извлечь ее из сессии, чтобы передать плагину фронт-контроллера в bootstrap-файле.
Контроллер User
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | user controller class UserController extends Zend_Controller_Action { protected $_application; public function init() { require_once 'Zend/Session/Namespace.php'; $this->_application = new Zend_Session_Namespace('myApplication'); } public function loginAction() { ... Код проверки авторизации if ($valid) { /** Сохранение роли в сессии */ $this->_application->currentRole = $user->role; $this->_application->loggedUser = $user->username; } } public function logoutAction() { $this->_application->currentRole = 'guest'; $this->_application->loggedUser = null; } } |
bootstrap-файл
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /** Загрузка данных приложения из сессии */ require_once 'Zend/Session/Namespace.php'; $application = new Zend_Session_Namespace('myApplication'); if (!isset($application->currentRole)) { $application->currentRole = 'guest'; } /** Установка фронт-контроллера */ require_once 'Zend/Controller/Front.php'; $front = Zend_Controller_Front::getInstance(); $front->setControllerDirectory('path/to/controllers'); /** Регистрация объекта плагина */ require_once 'Zend/Controller/Plugin/Acl.php'; $front->registerPlugin(new Zend_Controller_Plugin_Acl($myAcl, $application->currentRole)); /** Запуск диспетчеризации */ $front->dispatch(); |
3. Установка действия, отображаемого в случае запрета доступа
Возможно, некоторым из вас (надеюсь, никому =D) просто не понравится идея хранения действия, отображаемого в случае запрета доступа, в контроллере ошибок (error controller), или просто захочется иметь какой-то обходной путь. В этом случае вам поможет метод setErrorPage плагина фронт-контроллера.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /** Установка фронт-контроллера */ require_once 'Zend/Controller/Front.php'; $front = Zend_Controller_Front::getInstance(); $front->setControllerDirectory('path/to/controllers'); /** Установка действия, отображаемого в случае запрета доступа */ require_once 'Zend/Controller/Plugin/Acl.php'; $aclPlugin = new Zend_Controller_Plugin_Acl($myAcl, 'guest'); $aclPlugin->setErrorPage('goaway', 'my-error-controller', 'my-module'); /** Регистрация объекта плагина */ $front->registerPlugin($aclPlugin); /** Запуск диспетчеризации */ $front->dispatch(); |
К методу setErrorPage можно обратиться, указав только имя действия (в этом случае будут использованы имя контроллера и модуля по-умолчанию: ‘error’ и ‘default’ соответственно), но также можно передать методу действие и контроллер или все три параметра.
4. Использование помощника действий
В конце мы рассмотрим одну из наиболее важных частей этого предложения: как на примере devzone только авторам и администраторам разрешить редактировать статьи (Но, стоп: здесь есть упущенный момент. Если я – автор, и у меня есть доступ к article/edit/:id, в таком случае я смогу редактировать не только свои статьи, но и чужие. Это проблема, не так ли? Итак, что же нам теперь делать? Управлять с помощью помощника действий (Action Helper), который позволит обратиться к нашему ACL внутри любого контроллера, а не только во время запуска.
Итак, перво-наперво нам нужно зарегистрировать наш плагин фронт-контроллера и Controller Action Helper Broker.
Bootstrap-файл
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | /** Загрузка данных приложения из сессии */ require_once 'Zend/Session/Namespace.php'; $application = new Zend_Session_Namespace('myApplication'); if (!isset($application->loggedUser)) { $application->loggedUser = null; } /** Установка фронт-контроллера */ require_once 'Zend/Controller/Front.php'; $front = Zend_Controller_Front::getInstance(); $front->setControllerDirectory('path/to/controllers'); /** Регистрация объекта плагина */ require_once 'Zend/Controller/Plugin/Acl.php'; $front->registerPlugin(new Zend_Controller_Plugin_Acl($myAcl, $application->currentRole)); /** Регистрация объекта Action Helper */ require_once 'Zend/Controller/Action/Helper/Acl.php'; require_once 'Zend/Controller/Action/HelperBroker.php'; Zend_Controller_Action_HelperBroker::addHelper(new Zend_Controller_Action_Helper_Acl()); /** Запуск диспетчеризации */ $front->dispatch(); |
После регистрации помощника, мы можем использовать его внутри любого имеющегося контроллера. Поэтому давайте теперь разрешим редактирование только владельцам или любому из администраторов.
Контроллер Article
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | article controller class ArticleController extends Zend_Controller_Action { protected $_acl; protected $_application; public function init() { /** Получаем наш помощник действия (Action Helper) */ $this->_acl = $this->_helper->getHelper('acl'); require_once 'Zend/Session/Namespace.php'; $this->_application = new Zend_Session_Namespace('myApplication'); } ... public function editAction() { /** Получаем статью по id */ $article = new Article($this->_request->id); /** Проверяем, является ли пользователь владельцем или администратором */ if (($article->author != $this->_application->loggedUser) && ($this->_application->currentRole != 'admin')) { $this->_acl->denyAccess(); } ... } } |
Заключение
И последняя рекомендация: придерживайтесь принципа Оставлять Все Простым (Keep It Simple). Если вам не нужны динамически подгружаемые ACL, написанные руками правила – это не грех, это только лишь лучший способ реализовать необходимый функционал.
Автор статьи: Альдемар Берналь
Автор перевода: Кирилл Павлюков
Дополнительная информация:
Zend_Acl & MVC IntegrationА здесь вы найдете исходный код примеров к данной статье:
Исходный код
Оригинал статьи на DevZone:
http://devzone.zend.com/article/3510-Zend_Acl-and-MVC-Integration-Part-II-Advanced-Use

Свежие комментарии