我正在计划一个基于数据库的系统,该系统将支持分层多租户以及功能和特权的继承。原理图结构如下:
[0]
/ \
/ \
[1] [2]
/ / \
/ / \
[11] [21] [22]
/ \ \
/ \ \
[211] [212] [221]
/ \
/ \
[2211] [2212]
此处,表示层次结构中每个节点的数字仅为简单起见而设置,不应从中推断出任何数据。
第二个维度将由不同类型的用户给出,每个类型定义一组权限(例如,对系统正在处理的不同类型对象的访问类型)。
每个用户将分配给特定用户类型和特定租户(即上图中的节点)。分配给节点的用户将只具有可见性(如果分配了所需的权限) 相关用户类型)到同一租户内的对象和用户所属租户下的所有租户。
第三个维度将由以下事实给出:修改可以发生在分配给用户类型的默认权限上。例如,管理员用户类型可以创建新用户,但在子分支[221](和向下)除外。此例外将被定义为租户[221]的“掩码”。
因此,每当管理员登录其租户为[2212]的系统时,他收到的特权就是特权的超级位置:
Privileges defined at [2212] overriding the
privileges defined at [221] overriding the
privileges defined at [22] overriding the
privileges defined at [2] overriding the
privileges defined at [0]
例如,假设有5种不同的对象类型,即O1,O2,O3,O4和O5,权限为“N”(无),“R”(读取)和“W”(读取) /写)。默认情况下,管理员用户类型对所有对象类型都具有“W”特权。
现在,我们在节点[22]处的对象类型O3和O5上定义特权“R”,在级别[221]处定义对象类型O5的“N”特权。因此,分配给节点(租户)[2212]的管理员将继承以下权限:
Object Type O1 O2 O3 O4 O5
=================================================
From [0] W W W W W
From [2] _ _ _ _ _
From [22] _ _ R _ R
From [221] _ _ _ _ N
From [2212] _ _ _ _ _
------------------------------------------------
Result ===> W W R W N
现在,需要解决三个挑战:
当用户在节点(租户)X登录系统时,需要收集X的所有子节点以识别用户将(可能)具有可见性和操作权的对象,< / p>
当用户登录系统时,需要通过查看向上直到根节点来评估他的权限
数据库实现(SQL Server)的呈现方法是否合理?
在这三个问题中,“1”可以通过使用CTE来实现递归来简单地解决。然后我们留下问题2和3.我应该如何解决这个问题?
答案 0 :(得分:2)
如果您将权限表规范化为(admin_id, org_id, obj, perm)
而不是(admin_id, org_id, o1,o2,o3,o4,o5)
,则可以使用获取org id
的所有祖先的查询以及使用您正在查找的管理员的权限表,并获取最接近正在登录的节点的权限。
rextester设置:http://rextester.com/MZRF65032
create table org(id int not null primary key, parentid int null);
insert into org values
(0,null)
,(1,0),(11,1)
,(2,0),(21,2),(211,21),(212,21)
,(22,2),(221,22),(2211,221),(2212,221);
create table objects (obj char(2));
insert into objects values ('O1'),('O2'),('O3'),('O4'),('O5');
create table admin (id int not null primary key, name varchar(32));
insert into admin values (1,'Zim');
create table permissions(
admin_id int not null
, org_id int not null
, obj char(2)
, perm char(1)
);
insert into permissions (admin_id, org_id, obj, perm)
select 1, 0, obj, 'W' from objects
union all select 1, 22, 'O3', 'R'
union all select 1,221, 'O5', 'R'
union all select 1,221, 'O5', 'N';
在测试设置之后,一个选项如下:
/* without pivot */
;with cte as (
select
p.parentid
, p.id
, step=0
from org p
where p.id = 2212
union all
select
c.parentid
, c.id
, step=p.step+1
from org as c
inner join cte p on p.parentid = c.id
)
select o.obj, x.perm
from objects o
cross apply (
select top 1
perm.perm
from cte
inner join permissions perm on cte.id = perm.org_id
and perm.admin_id = 1
where perm.obj = o.obj
order by step
) as x
没有支点的结果:
+-----+------+
| obj | perm |
+-----+------+
| O1 | W |
| O2 | W |
| O3 | R |
| O4 | W |
| O5 | R |
+-----+------+
如果您需要将结果作为一行,则可以旋转上一个查询的结果:
/* with pivot */
;with cte as (
select
p.parentid
, p.id
, step=0
from org p
where p.id = 2212
union all
select
c.parentid
, c.id
, step=p.step+1
from org as c
inner join cte p on p.parentid = c.id
)
select o.obj, x.perm
from objects o
cross apply (
select top 1
perm.perm
from cte
inner join permissions perm on cte.id = perm.org_id
and perm.admin_id = 1
where perm.obj = o.obj
order by step
) as x
pivot (min(perm) for [obj] in ([o1],[o2],[o3],[o4],[o5])) as p
带有支点的结果:
+----+----+----+----+----+
| o1 | o2 | o3 | o4 | o5 |
+----+----+----+----+----+
| W | W | R | W | R |
+----+----+----+----+----+