Похоже это будет на права доступа в ОС Netware, т.е. элементы списка права доступа наследуются "на лету" с родительских объектов, соответственно, никаких тормозов при изменении прав доступа, но расчет эффективных прав будет требовать немного больше затрат. Реализованы также права доступа для "Владельца" объекта (смотри поле "Owner" в таблице "Objects").
Чтобы было понятнее, надо упомянуть, что в таблице "Objects" есть объекты с "предопределенными" ID:
пользователь "Системный администратор", ID=-100
псевдопользователь "Владелец объекта", ID=-102
тип связи "Группа-Пользователь", ID=-300
Нам понадобятся таблицы "Objects" и "Rights" с предыдущего поста и две хранимые процедуры:
CREATE TABLE "Objects" (
ID TIDNOTNULL NOT NULL /* TIDNOTNULL = INTEGER NOT NULL */,
"ClassID" TIDNOTNULL NOT NULL /* TIDNOTNULL = INTEGER NOT NULL */,
"ChildCount" TIDNOTNULL DEFAULT 0 NOT NULL /* TIDNOTNULL = INTEGER NOT NULL */,
"Creator" TIDNOTNULL DEFAULT -100 NOT NULL /* TIDNOTNULL = INTEGER NOT NULL */,
"Owner" TIDNOTNULL DEFAULT -100 NOT NULL /* TIDNOTNULL = INTEGER NOT NULL */,
"mUser" TIDNOTNULL DEFAULT -100 NOT NULL /* TIDNOTNULL = INTEGER NOT NULL */,
"OrderPos" TIDNOTNULL DEFAULT 0 NOT NULL /* TIDNOTNULL = INTEGER NOT NULL */,
"mTime" TCURTIMESTAMP DEFAULT current_timestamp NOT NULL /* TCURTIMESTAMP = TIMESTAMP DEFAULT current_timestamp */,
"cTime" TCURTIMESTAMP DEFAULT current_timestamp NOT NULL /* TCURTIMESTAMP = TIMESTAMP DEFAULT current_timestamp */,
"ParentID" TID /* TID = INTEGER */,
"State" TID /* TID = INTEGER */,
"Name" TSTR50 /* TSTR50 = VARCHAR(50) */,
"Desc" TSTR200 /* TSTR200 = VARCHAR(200) */,
GUID TGUID /* TGUID = CHAR(38) */
);
CREATE TABLE "Rights" (
"ObjID" TID NOT NULL /* TID = INTEGER */,
"UserID" TID NOT NULL /* TID = INTEGER */,
"Permissions" INTEGER NOT NULL
)
вспомогательная процедура pdm_GetACL
CREATE PROCEDURE "pdm_GetACL" (
"AObjID" integer,
"AUserID" integer,
"AGroupID" integer)
returns (
"ObjID" integer,
"TokenID" integer,
"Permissions" integer)
as
declare variable "tmpID" integer;
declare variable "OwnerID" integer;
begin
/*
Если AUserID и AGroupID равны null, то возвращаем полный ACL объекта
Если AGroupID is NULL, то возвращаем в иерархии родителей
первый ACE непосредственно для пользователя.
Если AGroupID is NOT NULL, то возвращаем первый ACE для указанной группы пользователя
в иерархии родителей объекта
Если встречается ACE непосредственно для пользователя, то выходим
ничего не возвращая, тем самым отсекаем ACE для групп, расположенные "дальше",
чем ACE для пользователя
*/
"ObjID" = "AObjID";
/*Если AUserID и AGroupID равны null, то возвращаем полный ACL объекта*/
if (("AUserID" is null) and ("AGroupID" is null)) then begin
for select "UserID", "Permissions" from "Rights"
where "ObjID"=:"AObjID"
into :"TokenID", :"Permissions" do suspend;
exit;
end
"Permissions" = 0;
select "Owner" from "Objects" where id=:"AObjID" into :"OwnerID";
while ("ObjID" is not null) do begin
--ищем ACE для пользователя
for select "UserID", "Permissions" from "Rights"
where "ObjID"=:"ObjID" and "UserID" = :"AUserID"
into :"TokenID", :"Permissions" do begin
if ("AGroupID" is null) then suspend;
exit;
end
--ищем ACE для владельца объекта
if ("AUserID" = "OwnerID") then
for select "UserID", "Permissions" from "Rights"
where "ObjID"=:"ObjID" and "UserID" = -102
into :"TokenID", :"Permissions" do begin
if ("AGroupID" is null) then suspend;
exit;
end
--ищем ACE для группы
if ("AGroupID" is not null) then
for select "UserID", "Permissions" from "Rights"
where "ObjID"=:"ObjID" and "UserID" = :"AGroupID"
into :"TokenID", :"Permissions" do begin
suspend;
exit;
end
-- получение следующего родителя
"tmpID" = "ObjID";
"ObjID" = NULL;
select "ParentID" from "Objects" where id = :"tmpID" into :"ObjID";
end
end
Основная процедура, возвращает эффективные права доступа к заданному объекту для заданного пользователя
CREATE PROCEDURE "pdm_GetObjPermissions" (
"AObjID" tid,
"AUserID" tid)
returns (
"Permissions" integer)
as
declare variable "tmpObjID" tid;
declare variable "tmpUserID" tid;
declare variable "tmpPerm" integer;
begin
/*
ACL - access control list (список прав доступа)
ACE - access control entity (элемент списка прав доступа),
это одна строка в таблице "Rights"(ObjID, UserID, Permissions)
В поле Permissions хранится битовое представление разрешений
(acRead=1;acWrite=2;acDelete=4;acReadChilds=8;acWriteChilds=16;acChangePermissons=32);
Правила расчета эффективных прав доступа на объект:
Если у объекта есть ACE непосредственно для пользователя, то возвращается
значение Permissions этого ACE.
Иначе права доступа наследуются следующим образом:
Ищется ближайший ACE для пользователя в родительской иерархии.
Для каждой группы, в которую входит пользователь, ищется ближайшее ACE
вверх по родительской иерархии, но ниже ACE для пользователя.
Т.е. если у какого-либо родителя существует ACE для пользователя, то такой
ACE имеет более высокий приоритет и "отсекает" все ACE для групп, расположенные
выше и на одинаковом уровне с ним.
Общее правило: ближе расположенный ACE для одного и того же пользователя или группы
имеет приоритет.
Найденные ACE для всех групп пользователя побитового суммируются друг с другом
и с ранее найденным ACE для пользователя.
*/
"Permissions" = 0;
/*Проверяем ACE непосредственно для пользователя*/
for select "ObjID", "Permissions"
from "pdm_GetACL"(:"AObjID",:"AUserID",NULL) into :"tmpObjID", :"Permissions" do
if ("tmpObjID" = "AObjID") then exit;
/*Проверяем ACE для групп пользователя*/
for select "ParentID" from "Links"
where "ChildID"=:"AUserID" and "LinkTypeID"=-300 into :"tmpUserID" do begin
for select "Permissions" from "pdm_GetACL"(:"AObjID",
:"AUserID", :"tmpUserID") into :"tmpPerm" do
"Permissions" = bin_or("Permissions", "tmpPerm");
end
end
И для наглядности, картинка:
Комментариев нет:
Отправить комментарий