Поделюсь с вами своим опытом в этом вопросе.
Задача:
Разграничение прав доступа по разделам сайта, с разными правами на каждый раздел, при этом они должны мнгновенно меняться если права для пользователя были изменены.
Тип сайта:
интранет.
Что будет использоваться:
Oracle, Zend Framework, Zend_Acl
Используем 3 таблицы, USERS, USERS_RIGHTS, MODULES
USERS:
USERS_RIGHTS:
MODULES:
Сайт построен таким образом, что модуль и контроллер должны быть указанны всегда (/module/controller). В результате Можно держать уникальные записи для каждого раздела. В моем случае это MODULES.SHORTNAME. В этом поле будут хранится связки module-controller, module-controller-action.
Добавим немного данных в таблицу MODULES:
В таблицу USERS:
В таблицу USER_RIGHTS:
Следующий шаг будет изменение booststrap.php файла. В него нужно добавить запись о настройке Zend_Acl. Так как я использую классову структуру этого файла, то мой вариант может отличаться от того, как вы это реализуете.
Немного обьяснения:
По правилам мы должны назвать роль, например «administrator» или «user», но это делать не обьязательно. Наш вариант включает уникальные права для каждого, которые заданы в таблице USER_RIGHTS. По-этому мы опускаем эту «формальность».
Далее мы выбираем все модули из таблицы (да, я знаю что это можно оптимизировать, но пока мы опускаем эту необходимость :)).
Присваиваем все модули и создает ресурсы под них.
Следующий шаг, это выбор прав пользователся: логика здесь такова, что мы выбираем все модули доступные пользователю и тип доступа, который хранится через запятую в поле USER_RIGHTS.TYPE.
И последним шагом является присвоение этих самых прав. И теперь когда мы будет проверять $acl->isAllowed(null, 'data-users', 'read') будем получать true, а если напишем вместо read какой-либо не существующий тип, то получим false. В общем то, к чему стремились.
Это пойдет в наш bootstrap.php:
Как вы могли заметить в планине нет ничего особенного… в принципе там нет ничего :) Просто это не весь функционал, который был в него заложен, но для ознакомление с этим вариантом этого достаточно.
Теперь можно запускать проверки в шаблонах в виде:
_CURRENT_MAIN_MODULE или _CURRENT_MODULE использовать в зависимости от надобности и выданных прав.
В контроллерах также нужно проверять $acl->isAllowed(); или же можно дописать немного плагин, который сам будет проверять, может ли человек смотреть тот раздел сайта, в котором находится.
Если кто-то заинтересуется более подробно этим вопросом, могу выложить demo код, который будет включать в себя все то, что мы здесь проделали :)
Задача:
Разграничение прав доступа по разделам сайта, с разными правами на каждый раздел, при этом они должны мнгновенно меняться если права для пользователя были изменены.
Тип сайта:
интранет.
Что будет использоваться:
Oracle, Zend Framework, Zend_Acl
1. База данных
Используем 3 таблицы, USERS, USERS_RIGHTS, MODULES
USERS:
CREATE TABLE "USERS" ( "ID" NUMBER NOT NULL , "USERNAME" VARCHAR2(50 BYTE) NULL , "PASSWORD" VARCHAR2(32 BYTE) NULL );
USERS_RIGHTS:
CREATE TABLE "USER_RIGHTS" ( "USER_ID" NUMBER NULL , "RULE" VARCHAR2(100 BYTE) NULL , "TYPE" VARCHAR2(500 BYTE) NULL );
MODULES:
CREATE TABLE "MODULES" ( "ID" VARCHAR2(20 BYTE) NOT NULL , "SHORTNAME" VARCHAR2(200 BYTE) NULL , "NAME" VARCHAR2(200 BYTE) NULL , "LINK" VARCHAR2(200 BYTE) NULL , "PARENT_ID" NUMBER NULL , "LANGUAGE" VARCHAR2(2 BYTE) DEFAULT 'lv' NULL );
Сайт построен таким образом, что модуль и контроллер должны быть указанны всегда (/module/controller). В результате Можно держать уникальные записи для каждого раздела. В моем случае это MODULES.SHORTNAME. В этом поле будут хранится связки module-controller, module-controller-action.
Добавим немного данных в таблицу MODULES:
INSERT INTO "MODULES" VALUES ('1', 'data', 'Данные', '/data', '0', 'ru'); INSERT INTO "MODULES" VALUES ('2', 'data-users', 'Пользователи', '1', 'ru');
В таблицу USERS:
INSERT INTO "USERS" VALUES ('1', 'demo_username', 'demo_password');
В таблицу USER_RIGHTS:
INSERT INTO "USER_RIGHTS" VALUES ('1', 'data', 'read'); INSERT INTO "USER_RIGHTS" VALUES ('1', 'data-users', 'read,add,edit,delete,search,export,history');
2. Настройка Zend_Acl
Следующий шаг будет изменение booststrap.php файла. В него нужно добавить запись о настройке Zend_Acl. Так как я использую классову структуру этого файла, то мой вариант может отличаться от того, как вы это реализуете.
public static function setupAcl() { $auth = Zend_Auth::getInstance(); if ($auth->hasIdentity()) { self::$acl = new Zend_Acl(); self::$acl->addRole(new Zend_Acl_Role(null)); $db = self::$registry->database; $sql = "SELECT shortname FROM modules WHERE ".$db->quoteInto("language = ?", $auth->getIdentity()->LANGUAGE); $modules = $db->fetchAll($sql); foreach ($modules as $v) self::$acl->add(new Zend_Acl_Resource($v['SHORTNAME'])); $sql = "SELECT rule,type FROM user_rights WHERE ".$db->quoteInto("user_id = ?", $auth->getIdentity()->ID); $rules = $db->fetchAll($sql); foreach ($rules as $v) { $perms = explode(',', $v['TYPE']); if (self::$acl->has($v['RULE'])) self::$acl->allow(null, $v['RULE'], array_values($perms)); } self::$registry->set('Zend_Acl', self::$acl); } }
Немного обьяснения:
self::$acl->addRole(new Zend_Acl_Role(null));
По правилам мы должны назвать роль, например «administrator» или «user», но это делать не обьязательно. Наш вариант включает уникальные права для каждого, которые заданы в таблице USER_RIGHTS. По-этому мы опускаем эту «формальность».
Далее мы выбираем все модули из таблицы (да, я знаю что это можно оптимизировать, но пока мы опускаем эту необходимость :)).
Присваиваем все модули и создает ресурсы под них.
Следующий шаг, это выбор прав пользователся: логика здесь такова, что мы выбираем все модули доступные пользователю и тип доступа, который хранится через запятую в поле USER_RIGHTS.TYPE.
И последним шагом является присвоение этих самых прав. И теперь когда мы будет проверять $acl->isAllowed(null, 'data-users', 'read') будем получать true, а если напишем вместо read какой-либо не существующий тип, то получим false. В общем то, к чему стремились.
3. Плагин для Фронт контроллера
class System_Rights extends Zend_Controller_Plugin_Abstract { public function preDispatch(Zend_Controller_Request_Abstract $request) { $db = Zend_Registry::get('Zend_Db'); $query = array(); $query[] = $request->getModuleName(); if ($request->getControllerName() != 'index') $query[] = $request->getControllerName(); if ($request->getActionName() != 'index') $query[] = $request->getActionName(); /* define module/controller/action like /data/users/add */ define('_CURRENT_MODULE', implode('-', $query)); /* define current main module/controller like /data/users */ if (count($query) > 2) array_pop($query); define('_CURRENT_MAIN_MODULE', implode('-', $query)); } }
Это пойдет в наш bootstrap.php:
$frontController->registerPlugin(new System_Rights());
Как вы могли заметить в планине нет ничего особенного… в принципе там нет ничего :) Просто это не весь функционал, который был в него заложен, но для ознакомление с этим вариантом этого достаточно.
4. View
Теперь можно запускать проверки в шаблонах в виде:
<?php if ($this->acl->has(_CURRENT_MAIN_MODULE) && $this->acl->isAllowed(null, _CURRENT_MAIN_MODULE, 'read')):?> Все окей прав достаточно <?php else:?> Уля ля, куда это вы ? <?php endif;?>
_CURRENT_MAIN_MODULE или _CURRENT_MODULE использовать в зависимости от надобности и выданных прав.
В контроллерах также нужно проверять $acl->isAllowed(); или же можно дописать немного плагин, который сам будет проверять, может ли человек смотреть тот раздел сайта, в котором находится.
Если кто-то заинтересуется более подробно этим вопросом, могу выложить demo код, который будет включать в себя все то, что мы здесь проделали :)