Интеграция Zend_Acl и MVC. Часть 1 (простейшее использование)
Перевод статьи “Zend_Acl and MVC Integration Part I (Basic Use)” Автор Aldemar Bernal
Итак, что не так с Zend_Acl и текущей реализацией MVC в Zend Framework? Ничего неправильного нет, просто не слишком очевидно для разработчиков, как достичь оптимальной интеграции между этими двумя важными частями фреймворка.
Во-первых, эта статья основана на следующем предложении (link), в настоящий момент находящемся в стадии Ожидания рекомендации.
Ну, как это работает? Существуют два основных компонента в этом предложении:
- Плагин фронт-контроллера (Front Controller Plugin): этот компонент решает, имеет ли доступ текущий пользователь к открываемой странице.
- Помощник действия (Action Helper): Этот компонент позволяет проверить, имеет ли текущий пользователь доступ внутрь контроллера.
Опираясь на эти два компонента, давайте попробуем их на примере. Давайте будем говорить о сайте, подобном DevZone.
Нам потребуется контроллер для управления пользователями и еще один контроллер для управления статьями, так же 3 типа пользователей (ролей): одну для гостей, одну для авторов статей и еще одну для утверждения статей. Итого, мы имеем:
Ресурсы:
- Контроллер пользователей.
- Контроллер статей.
Роли:
- Гость (Guest).
- Автор (Writer).
- Администратор (Admin).
Настройка компонента Zend_Acl
После определения того, что нам нужно сделать, следующим шагом будет создание экземпляра Zend_Acl, отражающего нашу модель.
/** Creating the ACL object */
require_once 'Zend/Acl.php';
$myAcl = new Zend_Acl();
Создание ролей
Сейчас мы создадим роли в нашем экземпляре Zend_Acl.
/** Creating Roles */
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');
Создание ресурсов
Создадим необходимые ресурсы (по одному на контроллер), а также их отношения с созданными нами ролями.
/** Creating resources */
require_once 'Zend/Acl/Resource.php';
$myAcl->add(new Zend_Acl_Resource('user'))
->add(new Zend_Acl_Resource('article'));
Создание привилегий
Теперь мы добавили роли и ресурсы в наш экземпляр Zend_Acl, пора объяснить, какие действия должны быть доступны для каких ролей.
- Гости не могут редактировать, добавлять и публиковать статьи.
- Авторы не могут публиковать статьи.
- Администраторы имеют полный доступ.
/** Creating permissions */
$myAcl->allow('guest', 'user')
->deny('guest', 'article')
->allow('guest', 'article', 'view')
->allow('writer', 'article', array('add', 'edit'))
->allow('admin', 'article', 'approve');
Создание страницы, отображаемой при отсутствии доступа
Нам нужно будет создать представление (view) и действие (action) на которое мы переадресуем всех пользователей, у которых недостаточно привилегий.
Во-первых, мы создадим новое действие в нашем контроллере ошибок:
class ErrorController extends Zend_Controller_Action
{
....
public function deniedAction()
{
}
....
}
Затем мы создадим наш файл представления (/application/views/scripts/error/denied.phtml) с некоторым предупреждающим сообщением:
<h1>Error</h1>
<h2>Access denied</h2>
<p>You are trying to access an area which you have not allowed.</p>
Завершение настройки
Хорошо, мы настроили наш экземпляр Zend_Acl. Следующий шаг - регистрация плагина контроллера. Это важная часть берет созданный нами экземпляр Zend_Acl и проверяет, доступна ли текущая страница пользователю.
/** Setting up the front controller */
require_once 'Zend/Controller/Front.php';
$front = Zend_Controller_Front::getInstance();
$front->setControllerDirectory('path/to/controllers');
/** Registering the Plugin object */
require_once 'Zend/Controller/Plugin/Acl.php';
$aclPlugin = new Zend_Controller_Plugin_Acl($myAcl);
$aclPlugin->setRoleName($currentUserRole);
$front->registerPlugin(new Zend_Controller_Plugin_Acl($acl, 'guest'));
/** Dispatching the front controller */
$front->dispatch();
После завершения настройки, как только пользователь войдет в наше приложение, в зависимости от его/её роли будет либо отображена запрошенная страница, либо страница с сообщением о запрете доступа.
Для более подробного ознакомления с темой вы можете почитать следующее:
Zend_Acl & MVC Integration
и небольшой пример:
Source Code
Популярность: 48%
Метки: ACL, tutorial, zend framework, перевод


июля 13, 2008 at 10:52
пишите полезную инфу, подберите скин для блога повеселее :)
июля 14, 2008 at 13:18
“Полезную” это какую?
А до скина уже с пол-года руки не доходят :(
июля 14, 2008 at 14:01
Скинов полно для вордпресса. Просто дефолтный уже всем приелся.
июля 14, 2008 at 14:10
Вот закрою текущий проект и займусь версткой скина…
июля 14, 2008 at 20:51
Сохранил статью в закладках, надо будет прочитать повнимательнее как наконец начну его изучать. Вообще Zend отличный фреймворк..
июля 17, 2008 at 10:41
[...] Лобач.info Заметки LAMP-программиста о вебдеве и не только… « Интеграция Zend_Acl и MVC. Часть 1 (простейшее использование) [...]
августа 17, 2008 at 19:44
Во первых когда скачал плагин и хелпер то они блин назывались не Zend_… а Zion_… пришлось все переименовывать,чтобы Zend_Loader::registerAutoload() работал((.Во вторых очень не нравиться то что для того чтобы обратиться к ЛЮБОМУ контроллеру(в понимании плогина как ресурса) приходится его объявлять как ресурс,а если скажем есть контроллер который всегда без всяких там прав должен открываться,ну хотя бы регистрация или еще что то там…Я поэтому решил скорректировать с децл код плагина (Zion_Controller_Plugin_Acl)- в методе preDispatch перед строчкой if (!$this->getAcl()->isAllowed($this->_roleName, $resourceName, $request->getActionName())) поставил условие if($this->getAcl()->has($resourceName)),чтобы проверить существует ли ресурс,теперь можно смело объявлять ресурсами только лишь те контроллеры на котроые действительно нужно контролить доступ.))))
августа 19, 2008 at 02:26
кстати,у меня возникла проблема-не перехватывается процесс дисперетчизации если я использую хелпер Zend_View action,то есть проблема вот какая в скрипте вида пишу action(’say’, ’say’); ?>,на который скажем гостю запрещен доступ,а он все равно ставновится виден…помогите пожаласта-не пойму че делать,чтобы ему доступ ограничивало)))
августа 19, 2008 at 11:58
@tatarin: честно говоря, не совсем понятно что у Вас работает не так, как надо.
Может быть опишете более подробно в чем проблема и сделаете архив с кодом, чтобы можно было посмотреть?
августа 19, 2008 at 13:52
ок,вечером зайду и выложу весь код в архиве…ато голова уже болит…я в гугловской группе по зенд фреймворк уже выложил мессагу..пока никто не откликнулся…ну я там суть проблемы описал ==>
В общем задача такая,чтобы мой плагин обошел все вызываемые пути,которые надо обработать в данном вызове,при запуске фронт контроллера(метод preDispatch в плагине) и просто их вывел……
У меня такая проблема-вызывается помощник action action(’say’, ’say’); ?> в скрипте вида say/index.tpl,тока вот почему то фронт контроллер не воспринимает то что запрос идет к say/say (в нашем случае из помощника action) а не к say/index (контроллер/действие)…объясните почему это и как это обойти…или я че то путаю?Может тут поможет ActionStack-я правда ничего не знаю о нем,но название такое что он в себе содержит вроде все запросы которые обработались по одному маршруту(в моем случае их 2-say/index и say/say).
Моя логика-он должен вывести по маршруту http://cs/say
–say/index
–say/say
А выводит зараза совсем нито))
Тут может еще preDispatch у всех контроллеров надо перегрузить,чтобы они ловили все вызовы к ним,но нельзя ли обойтись как нить без этого?
августа 19, 2008 at 22:07
Ну еще добавлю по проблеме:
данный плагин позволяет отслеживать доступ только лишь к тому маршруту,который задается через урл(при инстанировании фронт контроллера),а теперь представьте себе ,что мы запросили контроллер и дейтсвие через урл к которому доступ открыт,а вот в виде контроллера вызывается хелпер action(’действие к которому нельзя получить доступ’,'контроллер к которому нельзя получить доступ’)-так вот метод преддиспетчиризации в плагине не ловит этого и поэтому выводится содержимое запрещенного маршрута…поэтому в моей ситуации этот плагин оказался бесполезным(я роюсь уже 4 дня как все заствить это работать),так как вроде как он и не может ловить все маршруты вызываемые в процессе диспетчиризации…пришлось расширять класс Zend_Controller_Action и от него наследовать все остальные контроллеры….если вы разберетесь с этим и выложите идеи как ловить все маршруты то напишите,буду благодарен)))
августа 19, 2008 at 22:21
Это ведь плагин контроллера. А для решения Вашей задачи может стоит написать (или расширить стандартный) вью хелпер?
августа 19, 2008 at 22:23
На мой взгляд вполне нормальное решение. Что в нем плохого?
августа 19, 2008 at 23:16
Ну плохого вобщем то ничего нет…))Просто я ожидал что этот плагин выполнит то что о нем говорится(как только пользователь войдет в наше приложение, в зависимости от его/её роли будет либо отображена запрошенная страница, либо страница с сообщением о запрете доступа)…на счет вью-хелпера-это не то-придется постоянно его вызывать,а хочу чтобы все было автоматом-указал в файле настроек все и чтоб работало без лишнего кода….кстати когда писал класс возник интересный вопрос-
почему _forward в init() выдает ошибку
string(2092) “ERROR: Action “denied” does not exist and was not
trapped in __call()
#0 Z:\home\cs\www\libs\Zend\Controller\Action.php(518):
Zend_Controller_Action->__call(’deniedAction’, Array)
а если я его использую в init(),а если использую в preDispatch() то
все работает как надо?
августа 19, 2008 at 23:19
если надо класс кстати могу выложить))
августа 19, 2008 at 23:40
Ну, хуже от этого не будет ;)
августа 23, 2008 at 00:00
class MyAclController extends Zend_Controller_Action { /** * Pre-dispatch routines * * Called before action method. If using class with * {@link Zend_Controller_Front}, it may modify the * {@link $_request Request object} and reset its dispatched flag in order * to skip processing the current action. * * @return void */ public function preDispatch() { parent::preDispatch(); $myacl=Zend_Registry::get('myacl'); $resourceName = ''; $request=$this->getRequest(); if ($request->getModuleName() != 'default') { $resourceName .= $request->getModuleName() . ':'; } $resourceName .= $request->getControllerName(); if($myacl->has($resourceName)) if (!$myacl->isAllowed(AuthModel::get_my_role(), $resourceName, $request->getActionName())) { $setting_error_dostup_MVC=Zend_Registry::get('setting_error_dostup_MVC'); $modul='default'; $controller='error'; $action='denied'; $params=array(); $index_arr=$request->getModuleName().":".$request->getControllerName().":".$request->getActionName(); if(isset($setting_error_dostup_MVC[$index_arr])) { $arr=$setting_error_dostup_MVC[$index_arr]; if(isset($arr['modul']))$modul=$arr['modul']; if(isset($arr['controller']))$controller=$arr['controller']; if(isset($arr['action']))$action=$arr['action']; if(isset($arr['params']))$params=array('err_acl'=>$arr['params']); } $this->_forward($action,$controller,$modul,$params); } } }августа 23, 2008 at 00:03
кстати он не так работает когда идет пересыл в хелпере action-он вообще ничего не показывает если доступ запрещен вместо перенаправления…я не знаю почему..помогите если кто понимает в этом че))я вот уже голову сломал пока думал…просто берет и ничего не показывает…
ноября 16, 2008 at 22:25
>>“Полезную” это какую?
Имел ввиду пИшите, не призыв а констатация факта. А обложка, то есть скин блога, не привлекательная.
ноября 16, 2008 at 23:37
Я действительно понял фразу как призыв.
Да мне и самому не очень нравится, но до верстки нормального шаблона все никак руки не доходят.
ноября 17, 2008 at 00:13
Есть ведь масса других уже готовых шаблонов, скачал, залил, включил и может даже сразу работать :) в гугле очень быстро находятся http://www.google.com/search?hl=ru&q=шаблоны+wordpress
ноября 17, 2008 at 00:15
Кстати рекомендую поставить премодерирование только на первый комментарий с одного email. Так отсекается большая часть спамеров, а постоянные посетители сразу размещают комментарии, и общение более живое.