如何设计基于分层角色的访问控制系统
Posted
技术标签:
【中文标题】如何设计基于分层角色的访问控制系统【英文标题】:How to design a hierarchical role based access control system 【发布时间】:2013-04-14 22:02:19 【问题描述】:基本交易是,我们为我们的项目定制了一个“kickstart”。为此,我们正在考虑重做用户控件。我知道有很多关于一般 rbac 的问题,但我在分层 rbac 上找不到任何问题?
我们的要求是:
角色可以分配给组权限 如果角色没有权限条目,则会自动拒绝 可以为用户授予覆盖权限 用户覆盖权限是授予或拒绝 如果用户被明确拒绝权限,则无论哪个角色说“已授予”,覆盖都会获胜。 用户可以拥有多个角色 角色可以有层次结构 角色可以从其他角色继承(例如,“论坛超级版主”角色是“论坛版主”和“系统维护者”,“论坛版主”角色已经从“论坛用户”角色继承) 从拒绝或授予权限的其他角色继承的角色会覆盖其子权限 权限按“模块”分组(例如,“博客”模块可以有“编辑条目”权限,“论坛”模块可以有“编辑条目”权限,它们不会冲突) 有一个“Everything and Anything”权限会自动授予完全访问权限所以,这些要求已经排除,这就是我的想法。
表:用户
id | int | unique id
表:角色
id | int | unique id
--------------|---------------------------------------------
title | varchar | human readable name
表:权限
id | int | unique id
--------------|---------------------------------------------
module | varchar | module name
--------------|---------------------------------------------
title | varchar | human readable name
--------------|---------------------------------------------
key | varchar | key name used in functions
表:Role_User
role_id | int | id from roles table
--------------|---------------------------------------------
user_id | int | id from users table
表:Permission_Role
id | int | unique id
--------------|---------------------------------------------
permission_id | int | id from permissions table
--------------|---------------------------------------------
role_id | int | id from roles table
--------------|---------------------------------------------
grant | tinyint | 0 = deny, 1 = grant
表:Permission_User
id | int | unique id
--------------|---------------------------------------------
permission_id | int | id from permissions table
--------------|---------------------------------------------
user_id | int | id from users table
--------------|---------------------------------------------
grant | tinyint | 0 = deny, 1 = grant
嗯,实际上这是一半,我确定的那部分,我卡住的部分是等级角色。
那么,我该如何设计呢? 我的想法是,为了保存数据库查询,我将在登录时构建权限矩阵并将其保存到会话中,这样查询就不必太简单,因为它们每次登录只运行一次。
我看到的问题是,我需要知道角色的层次结构,以便在解决继承问题之前解决继承的角色权限。
用户权限是最简单的部分,每个用户的权限本质上是最终解决的组。
【问题讨论】:
user
没有role
但有permission
有什么原因吗?这是一个“许可模型”,而不是“角色模型”,不是吗?使用这种方法,角色不会在任何地方使用。
糟糕,忘记添加该表,已编辑!
不过,我认为user
没有理由拥有permission
。它可能有role
s 和permission
s,但不是permission
s。这件事破坏了逻辑(恕我直言)。
@CORRUPT,用户自己也可以被授予权限,这些权限会覆盖他们所在的任何角色。它可以避免仅仅因为您希望用户 X 能够创建具有一个权限的全新角色做一个额外的动作。或者,如果用户一直在做他们不应该做的事情,您可以快速拒绝该用户。否则你将不得不继承***别的角色,然后拒绝那里可能会变得混乱。
这很像说每个用户都是他们自己的角色,它自动继承自该用户被赋予的所有其他角色,而无需实际为该用户创建一个组。这有意义吗?
【参考方案1】:
有一种方法可以通过在表Roles
上使用递归关系来实现角色继承,方法是让角色引用另一条记录:
此关系将在Roles
记录中添加1 : n
继承。您可以使用此存储函数获得整个层次结构树:
CREATE FUNCTION `getHierarchy`(`aRole` BIGINT UNSIGNED)
RETURNS VARCHAR(1024)
NOT DETERMINISTIC
READS SQL DATA
BEGIN
DECLARE `aResult` VARCHAR(1024) DEFAULT NULL;
DECLARE `aParent` BIGINT UNSIGNED;
SET `aParent` = (SELECT `parent` FROM `Roles` WHERE `id` = `aRole`);
WHILE NOT `aParent` IS NULL DO
SET `aResult` = CONCAT_WS(',', `aResult`, `aParent`);
SET `aParent` = (SELECT `parent` FROM `Roles` WHERE `id` = `aParent`);
END WHILE;
RETURN IFNULL(`aResult`, '');
END
然后,您可能会通过以下方式获得所有授予权限:
SELECT
`permission_id`
FROM
`Permission_Role`
WHERE
FIND_IN_SET(`role_id`, `getHierarchy`($role))
AND
grant;
如果还不够的话,可以再做一张表继承:
但是,在这种情况下,需要另一个层次获得算法。
要解决覆盖问题,您必须获得角色权限和用户权限。然后,将user
权限写入roles
权限到session
。
另外,我建议删除Permission_Role
和Permission_User
中的grant
列。无需为每个权限映射每个权限。足以使用EXISTS
查询:如果有记录,则授予权限,否则 - 不是。如果您需要检索所有权限和状态,您可以使用LEFT JOIN
s。
【讨论】:
这听起来不错,我会研究一下,我肯定在考虑让每个角色继承多个其他角色,所以必须制定其他算法,如果我们不能这样做,也想知道怎么做创建存储过程?授予或拒绝的点不是列出每个权限,授予或拒绝的点是如果一个角色继承了另一个角色,如果继承的角色已被授予权限,则可以在继承角色中显式拒绝它以拒绝该权限。以上是关于如何设计基于分层角色的访问控制系统的主要内容,如果未能解决你的问题,请参考以下文章