问题描述
在我的应用程序中,我使用基于角色的访问控制来对用户进行身份验证和授权。可以为每个用户分配多个角色,这些角色提供对权限的访问。
每个角色都是层次结构的一部分,“已验证”角色位于树的顶部。所有其他角色都使用表中的自引用关系从中继承。默认角色表如下所示,具有从“已验证”继承的“主持人和开发者”角色和从“主持人”继承的“管理员”角色。
roles table
id name parent role
1 verified none
2 moderator verified
3 developer verified
4 admin moderator
向用户分配角色时,我要强制要求父母是必需的,这意味着如果用户具有管理员角色,则他们还必须具有主持人和已验证身份。这意味着,如果用户失去其主持人角色,则应自动删除其管理员角色,并且如果该管理员角色的父级更改为开发人员,则该用户应失去该管理员角色,因为他们不再具有所需的父级。 / p>
到目前为止,我想到的唯一解决方案包括在链接表上添加一个新列,以引用已分配的父级,例如:
role-user link table
id role user_id parent role-user link
1 verified 1 none
2 moderator 1 1
3 admin 1 2
这意味着,如果我从用户1中删除了主持人角色,他们将失去管理员角色,但是如果我将管理员角色的父级更改为开发人员,则不会从链接表中删除主持人和管理员角色。有没有一种方法可以仅通过sql /外键约束来实现此功能?
解决方法
假设您的表格结构如下:
create table role_user (
user_id int,role_id int,parent_role_id int,primary key (user_id,role_id)
);
层次结构关系在表本身中进行了描述。为了加强完整性,您可以在(user_id,parent_role_id)
上有一个自引用复合外键,该外键引用同一表中(user_id,role_id)
列的另一行。有了此设置后,您只需启用选项on delete cascade
即可获得所需的行为:
create table role_user (
user_id int,role_id),foreign key (user_id,parent_role_id)
references role_user(user_id,role_id)
on delete cascade
);
-- sample data
select * from role_user;
user_id | role_id | parent_role_id
------: | ------: | -------------:
1 | 1 |
1 | 2 | 1
1 | 3 | 2
-- delete the top node in the hierarchy
delete from role_user where user_id = 1 and role_id = 1;
-- all children rows are deleted as well
select * from role_user;
user_id | role_id | parent_role_id
------: | ------: | -------------: