framework.zend.com
Stable релиз 2.0 / 1.12

Zend_Acl часть 1 : Распространенные заблуждения и простые ACL

К комментариям

Содержание

От переводчика

Данный тест - перевод статьи Zend_Acl part 1: Misconceptions and simple ACLs автором которой является Jani Hartikainen. Большое спасибо Александру Махомету, и Александру Стешенко за помощь в работе над переводом. Следующие части статьи в русскоязычном варианте находятся в обработке.

Введение

ACL - access control list (cписок прав доступа).

Я начинаю серию статей о Zend_Acl. Первая статья познакомит вас с азами Zend_Acl. Для этого мы развеем некоторые распространенные заблуждения и научимся создавать простые списки прав доступа (ACL). Затем применим ACL в приложениях на базе Zend Framework и в качестве независимого компонента.

В последующих статьях данной серии я затрону более сложные способы использования Zend_Acl. В частности использование Zend_Acl совместно с базой данных.

Распространенные заблуждения о Zend_Acl

Многие думают, что такие понятия как “resource" (ресурс) and “privilege" (привилегия) тождественны таким понятиям как "controller" (контроллер) и “action “ (экшен, действие). Это не так.

Ресурсом в Zend_Acl может быть всё что угодно: модель, контроллер, файл и т.д.

Аналогично привилегией может быть всё, что так или иначе связано с ресурсом. К примеру привилегией может быть действие, если ресурсом является контроллер. Или разрешение на «чтение» или «запись», если ресурсом является файл или модель.

В последующих статьях данной серии я расскажу о других способах использования ресурсов, привилегий и ролей.

Построение простого ACL

Как мы выяснили, Zend_Acl состоит из ресурсов (resources), привилегий (privileges) и ролей (roles). Ресурсом может быть абсолютно всё что угодно. Привилегиями являются различные уровни доступа к ресурсу. Ролями могут выступать пользователи, группы, и т.д. Роль определяет того, кто имеет доступ к ресурсу и какими привилегиями он обладает.

Самый простой способ использования Zend_Acl заключается в настройке правил ACL в самом коде. В целом это довольно неплохой подход для простых случаев, то есть в тех случаях, когда у вас небольшое количество ролей и ресурсов.

class My_Acl extends Zend_Acl {
public function __construct() {
// Создание новой роли guest («гость»)
$this->addRole(new Zend_Acl_Role('guest'));

// Создание роли user («пользователь») которая наследует роль guest
$this->addRole(new Zend_Acl_Role('user'), 'guest');

// Создаём ресурс page («страница»)
$this->add(new Zend_Acl_Resource('page'));

// Создаём ресурс news («новости») который наследует ресурс «страницу»
$this->add(new Zend_Acl_Resource('news'), 'page');

// Разрешаем гостю просматривать страницы
$this->allow('guest', 'page', 'view');

// Разрешаем пользователю комментировать новости.
$this->allow('user', 'news', 'comment');
}
}

Создание нового экземпляра объекта My_Acl позволит проводить простые проверки доступа согласно ACL. Давайте разберём этот пример подробно.

Роль guest («гость») получает привилегию view («просмотр») на доступ к ресурсу page («страница»). Роль «пользователь» наследует роль «гость», соответственно роль «пользователь» наследует и привилегии роли «гость». Аналогично ресурс «новости» наследует ресурс «страница». Таким образом, все у кого есть привилегии на доступ к ресурсу «страница» автоматически имеют такие же привилегии и к ресурсу «новости». В конце мы добавили «пользователю» привилегию комментирования «новостей». Таким образом, только обладатели роли «пользователь» имеют привилегию комментировать новости.

Обратите внимание: имена, которые были использованы для ролей и ресурсов являются просто идентификаторами. Они могут быть любыми. Например "1" или "2", в общем чем угодно. Но лучше использовать идентификаторы, которые интуитивно понятны. Однако когда вы генерируете ACL из базы данных или из другого источника, создание «удачных» имён может вызывать трудности, и не всегда на этом стоит заострять внимание. В таком случае неплохим идентификатором будет первичный ключ строки в таблице базы данных. Позже в статьях этой серии я познакомлю вас с подобным примером.

Использование простого ACL

Использовать класс ACL довольно просто. Всё что нужно сделать – это вызвать метод isAllowed() (проверка наличия права). Передав ему в качестве параметров роль, ресурс и привилегию. Основная сложность заключается в определении роли, ресурса и привилегии.

Как мы определим роль? Например, с помощью условного выражения. Если пользователь авторизирован, то его роль «пользователь», в противном случае - «гость».

Теперь разберёмся с ресурсом. В зависимости от приложения, мы можем выбрать имя ресурса, исходя из имени подключаемого файла. В нашем простом примере могут быть использованы файлы с именами page.php и news.php. Тогда ресурс «page» будет отвечать за page.php, а ресурс «news» - за news.php.

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

Небольшой пример:

$role = 'guest';
if(isset($_SESSION['auth']))
$role = 'user';

$acl = new My_Acl();

if($acl->isAllowed($role, 'news', 'comment')) {
// код для вывод блока комментирования
}

Как вы смогли убедиться, использовать Zend_Acl довольно просто. Даже без полноценного использования Zend Framework вы можете с лёгкостью ускорить разработку ваших приложений.

Наш пример очень прост, но он показывает основы использования ACL.

Использование простого ACL в Zend Framework приложениях.

В приложениях на основе Zend Framework ресурс и привилегия часто могут быть определены из обьекта запроса.

Создадим небольшой плагин который будет проверять ACL.

class My_Plugin_Acl extends Zend_Controller_Plugin_Abstract {
private $_acl = null;

public function __construct(Zend_Acl $acl) {
$this->_acl = $acl;
}

public function preDispatch(Zend_Controller_Request_Abstract $request) {
// Как и в предыдущем примере, аутентифицированные пользователи будут иметь
// роль «пользователь»
$role = (Zend_Auth::getInstance()->hasIdentity())
? 'user'
: 'guest';

// В этом примере мы будем использовать контроллер в качестве ресурса.
$resource = $request->getControllerName();

if(!$this->_acl->isAllowed($role, $resource, 'view')) {
// Если недостаточно прав то мы перенаправляем его на страницу авторизации
$request->setModuleName('auth')
->setControllerName('auth')
->setActionName('login');
}
}
}

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

Теперь, создав плагин, добавим его во front controller в загрузчике.

$acl = new My_Acl();

// $fc – front controller
$fc->registerPlugin(new My_Plugin_Acl($acl));

Теперь каждый запрос будет проходить проверку ACL, и никто не сможет «пройти внутрь», не имея привилегии просмотра.

Обратите внимание: Если вы используете класс My_Acl «как есть», это может вызвать запуск бесконечного цикла! Код плагина перенаправляет вас на страницу авторизации. После этого проверяется доступ к странице. Для этого всё так же используется имя контроллера в качестве идентификатора ресурса. Но в My_Acl нет ресурса, который называется auth! Итак, если вы хотите чтобы этот пример заработал, вам необходимо добавить ресурс auth в ACL.и наследовать auth от page, так как «гость» уже имеет необходимые привилегии к ресурсу page.

Как проверить привилегию комментирования?

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

public function someAction() {
$role = (Zend_Auth::getInstance()->hasIdentity())
? 'user'
: 'guest';

// Предполагаем что $this->_acl содержит acl
$this->view->canComment = $this->_acl->isAllowed($role, 'news', 'comment');
}

Будет неплохо изменить код таким образом, чтобы избежать двойной проверки роли. Например вы можете хранить роль в идентификаторе пользователя (прим переводчика Zend_Auth::getIdentity()) . Или создать action helper для доступа в ACL и содержащий все необходимые данные.

Вторая часть. Третья часть.

Тема на форуме

метки: Zend_Acl, ACL
Лучший способ следить за обновлениями сайта это подписаться на RSS
Если информация была полезной для вас, вы можете поддержать сайт.
Комментарии:
w1zard 04.04.2009 16:50 #
Спасибо за статью! Хорошая работа ;)
Как раз использую acl как в примере с плагином, это очень удобно, имхо. Хочу поинтерисоваться, а правильно будет хранить acl в реестре? Например, нужны тонкие проверки, которые не привязаны к контроллерам как ресурсам.
Ответить
rashad 04.04.2009 22:45 #
Я сам ACL только осваиваю, но на мой взгляд а реестре лучше не хранить. лучше поднимать из базы данных или создовать свои классы - ресурсы.
Ответить
Piom 23.04.2009 07:49 #
А если нет базы? Зачем на элементарые ресурсы заводить отдельные обьекты?
Ответить
Piom 23.04.2009 07:48 #
Месо хранения уже на ваше усмотрение. Если вы делаете из реестра помойку то почему бы и нет? Хотите  в конфиг запихайте, из базы цепаните, в файл зашейте, определите хоть в файле плагина, от этого ничего не изменится. самое главное что бы вам было понятно, и тем кто работает с вами.
Ответить
IgorN 06.04.2009 09:27 #
Статья хорошая, хотя бульшую часть материала можно прочитать и в офицеальном мануале. Я бы начал читать именно оттуда. А вот часть про использование самая полезная.
Фраза "Распространенные заблуждения о Zend_Acl" не корректна:
1. В базовом варианте как пишут и в офицеальном мануале и на девзоне, а так же многие другие гуру зф. Ресурс это как раз связка модуль + контроллер + экшен, где экшен может быть привилегией, а модуля или контроллера может и не быть(вместо них может идти привязка к URI).
А дуступ к файлу и т.д. это уже расширенный вариант использования.
2. Zend_ACL ветекает из REST архитектуры. Этим и объясняется понятия ресурса.

Поэтому заголовок мне не понравился. Нет там заблуждений, есть базовое использование и расширенное.  
Ответить
Piom 23.04.2009 07:54 #
К сожаление это как раз и есть заблуждение. Так как некоторые просто до костного мозга понимают ресурсы, привелегии ACL как контроллер, действие. Но это не так, из-за такой условности начинающию могут просто не понять гибкость acl? и в дальнейшем шпарить только как контроллер действие.
Расширенный вариант? у него всего один - дать возможность проверки и всё. А вот семафорить или логировать это уже доп. возможности!
Ответить
Dr0n 06.04.2009 13:09 #
Спасибо, за перевод. Недавно только изучал в оригинале, и приятно увидеть на родном языке.
ps. На самом деле интереснее будет в продолжении.
Ответить
ZloY 10.04.2009 07:56 #
Да спасибо, я подчерпнул для себя много нового, просто и понятно, здорово бы было прочитать  про динамический ACL в таком же понятном изложении
Ответить
Ion 23.09.2009 22:32 #
Спасибо за отличную статью!
Ответить
Олег 24.08.2010 09:00 #
Скажите, пожалуйтса, где хранить плагин, я пробовал в Application, но Bootstrap не находит.
Ответить
Александр 10.04.2011 10:20 #
Я только начинаю осваивать ZF. Ваша статья понравилась, спасибо большое. Был бы здорово, если бы более подробно было описано разбиение кода по структуре ZF, либо был бы приложен архив проекта. Я лично запутался, куда ложить код плагина My_Plugin_Acl, куда My_Acl, как и где потом подгружать эти файлы? Заранее благодарен.
Ответить
Уважаемые пользователи. Комментарии не для того чтобы:
  1. Спрашивать почему у вас не работает код, для этого есть тема форума закрепленная за статьей.
  2. Спрашивать как реализовать ту или иную функциональность, для этого необходимо создать свою тему на форуме.

Комментарии для того чтобы: высказать свое аргументированное мнение о статье, указать какие участки вызывают непонимание, что нужно исправить/улучшить, просто сказать спасибо.

Комментарии имеют древовидную структуру.
Если вы хотите ответить на определенный комментарий - нажмите на ссылку "Ответить" возле этого комментария.

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