Pull to refresh

Практикум Zend Framework. Часть третья: Zend_Acl

Reading time 4 min
Views 2.7K

Сегодня мы рассмотрим пример создания 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');
    }
}

И сразу проверим что все работает как мы ожидали:
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», что очень удобно в небольших проектах.
Tags:
Hubs:
+13
Comments 21
Comments Comments 21

Articles