Сегодня мы рассмотрим пример создания Acl для системы с большим количеством ролей и ресурсов.
-
- Аутентификация - вход пользователей в систему
- ACL - распределение прав доступа
-
Часть вторая
- Маршрутизация - настройка url для различных компонентов системы
- Registry - быстрый доступ к системным константам
-
Часть третья
- Acl - расширенный пример
Хабраюзер Anexroid любезно предоставил описание такого проекта:
Существуют следующие права доступа: Админ, с доступом в админку. Причем в админке порядка 20-30
разделов, 5 админов. У всех доступ разный. То есть у кого-то 2-3 раздела, у кого-то — все 20. Все
пункты меню храняться в БД. Пользователь — зарегестированный на сайте. Может создавать фотоальбомы,
комментировать новости без ввода капчи и т.д. + всё то, что может делать гость.Предприятие — имеет
личную страницу в каталоге, в зависимости от купленного пакета — различные пункты в личном кабинете.
Ну и гость, который может всё неограниченно просматривать. Комментарии — с капчей.Еще есть
консультанты — отвечают на вопросы в консультациях.Причем у предприятий и консультантов — нет
регистрации, добавляются админом. +опять же, все таблицы в БД отдельные — отдельно админы, отдельно
пользователи, отдельно — предприятия, отдельно — консультанты.
Для начала определимся с ролями и ресурсами, составим иерархии наследования ресурсов и ролей:
В нашем примере верхняя часть иерархия ресурсов будет совпадать по структуре с иерархией ролей. Для того чтобы, удобно отобразить иерархию ресурсов, добавим в наш список прав доступа абстрактные ресурсы для каждой роли, кроме Admin1-N, CompanyPackage1-N. Это так, потому что ресурсы для статусов Guest, User и общие ресурсы для всех админов и компаний имеют простую древовидную структуру, чего нельзя сказать про нижние узлы дерева в которых будут пересечения. Например Admin1 и Admin2 могут иметь доступ к общему ресурсу "Добавление новостей", а деревья ресурсов Zend_Acl, к сожалению, не поддерживает множественное наследование. Поэтому ресурсы для ролей Admin1-N, CompanyPackage1-N будут распределятся как исключения, явно назначаясь нужным ролям.
Итак, мы разобрались с иерархией ресурсов, теперь создадим непосредственно Acl. Для этого расширим класс Zend_Acl:
<?php
class Acl extends Zend_Acl {
public function __construct() {
// Добавляем роли
$this->addRole('guest');
$this->addRole('user', 'guest');
$this->addRole('admin', 'user');
$this->addRole('company', 'user');
$this->addRole('company-package-1', 'company');
$this->addRole('company-package-2', 'company');
$this->addRole('company-package-3', 'company');
// ...
$this->addRole('admin-1', 'admin');
$this->addRole('admin-2', 'admin');
// ...
$this->addRole('admin-5', 'admin');
//Добавляем ресурсы
//
// РЕСУРСЫ ГОСТЯ !
$this->add(new Zend_Acl_Resource('guest_res'));
// перечисляем все ресурсы гостя, как дочерние для guest_res
$this->add(new Zend_Acl_Resource('add-comments-with-captcha'), 'guest_res');
// РЕСУРСЫ ПОЛЬЗОВАТЕЛЯ !
$this->add(new Zend_Acl_Resource('user_res'));
// перечисляем все ресурсы пользователя, как дочерние для user_res
$this->add(new Zend_Acl_Resource('add-comments'), 'user_res');
// РЕСУРСЫ АДМИНА !
$this->add(new Zend_Acl_Resource('admin_res'));
// перечисляем общие ресурсы для всех админов, как дочерние для admin_res
$this->add(new Zend_Acl_Resource('admin-tools-list'), 'admin_res');
// РЕСУРСЫ КОМПАНИИ !
$this->add(new Zend_Acl_Resource('company_res'));
// перечисляем общие ресурсы для пакетов компаний, как дочерние для company_res
$this->add(new Zend_Acl_Resource('show-company-statistics'), 'company_res');
// Специфические ресурсы для админов и компаний, ничего не наследуют
$this->add(new Zend_Acl_Resource('advertise'));
$this->add(new Zend_Acl_Resource('add-company'));
//Выставляем права, по-умолчанию всё запрещено
$this->deny(null, null, null);
$this->allow('guest', 'guest_res', 'show');
$this->allow('user', 'user_res', 'show');
$this->allow('admin','admin_res', 'show');
$this->allow('company','company_res', 'show');
// Выставляем ресурсы для пакетов компаний и админов
$this->allow('company-package-1','advertise', 'show');
$this->allow('admin-1','add-company', 'show');
}
}
И сразу проверим что все работает как мы ожидали:
<?php
// ...
echo $acl->isAllowed('guest', 'add-comments-with-captcha', 'show')?'yes':'no'; // yes
echo $acl->isAllowed('guest', 'add-comments', 'show')?'yes':'no'; // no
echo $acl->isAllowed('admin-1', 'add-company', 'show')?'yes':'no'; // yes
echo $acl->isAllowed('company-package-2', 'advertise', 'show')?'yes':'no'; // no
В данном примере я разрешил себе сделать упрощение и ввел одну привилегию show, которая соответствует возможности просмотра определённой страницы. Однако вы можете расширить этот пример и добавить различные привилегии, если это потребуется.
Также, очевидно, что данный код не соответствует тому, что пакеты компании и администраторы будут добавляться, а права других ролей могут меняться со временем. Поэтому вам нужно будет хранить данные в базе данных и, либо строить объект по требованию, извлекая необходимые данные, или хранить сериализованный экземпляр класса Acl в каком либо хранилище (например memcached). Этот выбор за вами, лично мне больше нравится второй вариант.
В первом посте данного цикла я рассматривал как можно создать Acl используя в качестве ресурсов строки типа "controller/action", что очень удобно в небольших проектах.