Похоже это будет на права доступа в ОС 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
И для наглядности, картинка:
Комментариев нет:
Отправить комментарий