Это перевод второй части статьи с 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
Автор: Кирилл Павлюков
\\ Метки: PHP, Zend Framework, Zend_Acl, перевод, пример
Свежие комментарии