Здравствуйте.
Сейчас я расскажу вам про один из инструментов для разграничения прав пользователей/групп на вашем сайте – Zend_Acl.
Этот класс входит в PHP-фреймворк Zend Framework. Несмотря на то, что Zend Framework – цельная система, и её компоненты связаны между собой, класс Zend_Acl может без особых проблем использоваться отдельно.

Первое, что нужно сделать – установить нужную директорию для подключения файлов. Например, если наш каталог Zend мы поместили в каталог library, то нам понадобится использовать следующий код:

1
set_include_path('library');

Как вы уже, наверное, догадались, указать в set_include_path надо каталог, расположенный на уровень выше каталога Zend. Это не моя прихоть, иначе Zend_Acl не сможет подгрузить некоторые свои классы.

Для проверки, попробуйте выполнить следующую строку:

1
2
3
require_once('Zend/Acl.php');
$acl = new Zend_Acl;
var_dump($acl);

Если ошибки не произошло и на экран вывелся дамп объекта $acl, то всё в порядке и можно продолжать. Иначе вам придётся вернуться к предыдущему этапу и проверить правильность указанных путей.

В Zend_Acl cуществует несколько классов:
Zend_Acl – основной класс, который управляет всей работой.
Zend_Acl_Resource – класс для хранения ресурса. Для каждого ресурса используется отдельный экземпляр класса. Что такое ресурс, я полагаю, объяснять не нужно. Ресурс – это нечто, к чему запрашивают доступ. Есть ещё и другой термин – «Роль». Роль – это нечто, что запрашивает доступ к ресурсу. Например, если пользователь пытается открыть веб-страницу, то веб-страница – ресурс, а пользователь – роль.
Zend_Acl_Role служит для хранения роли. Что такое роль смотрите парой строк выше.
Zend_Acl_Role_Registry управляет множеством ролей (объектов Zend_Acl_Role)

Пришло время практики.

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
38
//подключаем необходимые классы
require_once('Zend/Acl.php');
require_once('Zend/Acl/Role.php');
require_once('Zend/Acl/Resource.php');

//инстанцируем класс, который будет управлять правами доступа
$acl = new Zend_Acl;

//инстанцируем классы ролей (гость, пользователь, администратор)
$roleGuest = new Zend_Acl_Role('guest');
$roleUser = new Zend_Acl_Role('user');
$roleAdmin = new Zend_Acl_Role('admin');

//передаём роли в Zend_Acl
$acl->addRole($roleGuest);
$acl->addRole($roleUser);
$acl->addRole($roleAdmin);

//инстанцируем классы ресурсов
$resourceAdminpanel = new Zend_Acl_Resource('adminpanel');  //доступно только администратору
$resourcePage = new Zend_Acl_Resource('film');

//передаём ресурсы в Zend_Acl
$acl->add($resourceAdminpanel);
$acl->add($resourcePage);

$acl->allow('admin');  //разрешаем доступ админу ко всем ресурсам
$acl->allow('user', 'film');  //разрешаем доступ пользователю к фильмам
$acl->allow('guest', 'film', 'view');  //разрешаем гостю только просматривать фильмы

echo $acl->isAllowed('admin', 'film', 'post') ? 'Администратор может публиковать фильмы' : 'Администратор не может публиковать фильмы';

echo $acl->isAllowed('user', 'film', 'post') ? 'Пользователь может публиковать фильмы' : 'Пользователь не может публиковать фильмы';

echo $acl->isAllowed('guest', 'film', 'post') ? 'Гость может публиковать фильмы' : 'Гость не может публиковать фильмы';

$acl->deny('user', 'film', 'post');
echo $acl->isAllowed('user', 'film', 'post') ? 'Пользователь может публиковать фильмы' : 'Пользователь не может публиковать фильмы';

Вот, собственно, и всё. Как видите, ничего сложного.
За подробностями отсылаю вас к документации по Zend_Acl и Zend Framework API

18 Comments

  1. Talant says:

    Ведь мы работаем только с именем ресурса. А как ресурсу задается имя?

  2. admin says:

    Имя ресурса передаётся в конструктор класса Zend_Acl_Resource.
    Например, создание ресурса с именем ‘film’:
    $resourcePage = new Zend_Acl_Resource(‘film’);

  3. lirien says:

    Не понял.. с именем топонятно…
    а как это имя ресурса связывается с
    адресом http://localhost/films/add

    Ведь ресурс это какоето конкретное действие..
    какогото конкретного контроллера

    как имя связывается именно с тем действием
    какое нужно, а не с другим..

    Вот :)

  4. admin says:

    2 lirien:
    Никак не связывается :)
    В Zend_Acl нет функционала для связывания действия контроллера и ресурса acl. На мой взгляд такая возможность была бы избыточным функционалом – слишком часто такой вариант не подходит.

    Проверка, доступен ли ресурс пользователю, производится при помощи метода isAllowed() класса Zend_Acl. Очень удобно :)

  5. lirien says:

    Ок, спасибо :)

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

    Написано, что нужно пользоваться функцией serialize()

    Я так понимаю, простейшая схема работы:
    1. В процессе аутентификации выясняется какая роль у пользователя
    2. В начале каждого действия в контроллере мы делаем unserialize()
    3. Проверяем isAllowed()
    3. Дальше действуем в зависимости от предоставленного доступа..

    Вопросы:
    1. Действительно ли нужно unserialize() делать при каждом действии?
    2. serialize() достаточно делать только для класса Zend_Acl?
    3. Можете ли подкинуть ссылки где пример с использованием Базы данных для хранения списков acl..

  6. admin says:

    2 lirien:
    Храните ваш объект Zend_Acl в Zend_Registry – не понадобится никакой сериализации.
    Я в своих проектах именно так и поступаю.

  7. lirien says:

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

    Или serialize всетаки нужна?
    Но unserialize делать только в базовом index.php
    и десериализованный класс записывать в реестр

    Так?

  8. admin says:

    2 lirien:
    Zend_Registry хранит данные в собственном же объекте – синглетоне. И, следовательно, уничтожаются они после выполнения скрипта.

    Храните ваши правила Zend_Acl в конфиге, на основе которого будет инсанцироваться Zend_Acl. Инстанцирование будет происходить с каждым новым запуском скрипта.

  9. lirien says:

    Вот спасибо :)
    Это то я и хотел узнать.

  10. admin says:

    Не за что :)

    Может подскажешь, на какую тему касательно ZF ты хотел бы увидеть здесь пояснения?

  11. lirien says:

    Если честно, в документации много всего есть.. :)

    Так, на вскидку, хотелось бы внятную статью по работе
    ZF с AJAX. Возможно таковая уже существует, пока не смотрел..

  12. Rauan says:

    Кстати, когда версия ZF была еще только 1.0.* в форумах выдвигали пропозал для возможности добавления ресурсов не по именам, а по контроллерам/действиям (даже регекспами). В ходе дискуссий даже предлагали сделать интеграцию с роутерами.

    Интересно, реализовали ли это? Была бы очень крутая фича…

  13. admin says:

    Согласен, было бы полезно. Можно даже попробовать реализовать :)

  14. Oleg Lobach says:

    Недавно на девзоне была пара статей – своего рода введение в использование ACL в ZF. Перевод я выложил в своем блоге.

  15. Dexter says:

    ну ниче так тем более что портировано уже для многих фреймворков

  16. andrey says:

    Такой пример. Гостевая книга.
    Таблица имеет колонки: ид, владелец_ид, текст, дата_написания, дата_последнего_изменения.
    Посетители могут просматривать все записи
    Зарегистрировавшись, пользователь может добавлять записи. И может править и удалять СВОИ предыдущие записи.
    Админ (их может быть несколько) может править и удалять ВСЕ записи
    Как это реализовать с помощью Zend_Acl и Zend_Auth?

  17. excalibur says:

    Сейчас как раз работаю с Zend_Acl. Нужно разработать интерфейс по управлению прав пользователей для удобного использования администратором в админ-части. Кто-то разрабатывал такой интерфейс? У меня пока только идеи одни, вот такой хардкод только на первое время подойдет, но нужно более гибкое решение, т.е. связка Zend_Acl+Zend_Db.

Leave a Reply