我有4张桌子,
权限
id | 蛞蝓 | 允许 |
---|---|---|
1 | 创建 | 真实 |
2 | 编辑 | 真实 |
3 | 删除 | 真实 |
4 | 编辑 | 假 |
角色
id | 蛞蝓 |
---|---|
1 | 管理员 |
2 | 经理 |
3 | 用户 |
模型_权限
模型类型 | 型号_id | permission_id |
---|---|---|
用户 | 1 | 4 |
角色 | 1 | 1 |
角色 | 1 | 2 |
角色 | 1 | 3 |
模型_角色
模型类型 | 型号_id | 角色_id |
---|---|---|
用户 | 1 | 1 |
用户 | 2 | 1 |
用户 | 3 | 2 |
用户 | 3 | 3 |
在第一步中,我想获得用户的所有权限(假设 id=1),无论是“直接”分配还是通过角色, 这就是我想到的,它有效并返回正确的结果
select p.*
from permissions p
join model_permissions mp on mp.permission_id = p.id
join model_roles mr on mr.model_type = 'users' and mr.model_id = 1
where
(
(mp.model_type = 'users' and mp.model_id = 1)
or
(mr.role_id = mp.model_id and mp.model_type = 'roles')
)
group by p.id;
我的下一步是检查用户是否具有特定权限,但是否有一行具有相同的
slug
和 allowed=false
我想得到空结果。
示例: id=1 的用户通过角色拥有
edit
权限 (allowed=true),还具有直接 edit
权限 (allowed=false) id=4(model_permissions 表),
因此,当我尝试检查用户是否具有
edit
权限时,在这种特殊情况下我想得到空(假)结果,我尝试过的
select p.*
from permissions p
join model_permissions mp on mp.permission_id = p.id
join model_roles mr on mr.model_type = 'users' and mr.model_id = 1
where
(
(mp.model_type = 'users' and mp.model_id = 1)
or
(mr.role_id = mp.model_id and mp.model_type = 'roles')
)
and
not exists(select *
from permissions p2
where p2.allowed=false
and p2.slug=p.slug
)
and
p.slug = 'edit'
group by p.id;
它按预期工作,但是如果我从 model_permissions 中删除行
|users | 1 | 4 |
它仍然返回空,我想获得结果,因为该用户通过角色具有“编辑”权限
我已经尝试过上面的sql查询,当我在
p2.id=p.id
语句中使用not exists
时,它总是返回结果,具有allowed=true
值的结果:| 2 | edit | true |
无需更改数据库架构的任何解决方案
修改后应该能满足您的需求了
SELECT p.*
FROM permissions p
JOIN model_permissions mp ON mp.permission_id = p.id
LEFT JOIN model_permissions mp_direct ON mp_direct.permission_id = p.id AND mp_direct.model_type = 'users' AND mp_direct.model_id = 1
JOIN model_roles mr ON mr.model_type = 'users' AND mr.model_id = 1
WHERE
-- Either direct user permission or through roles
(
(mp.model_type = 'users' AND mp.model_id = 1)
OR
(mr.role_id = mp.model_id AND mp.model_type = 'roles')
)
-- Ensure we're checking for the specific permission
AND p.slug = 'edit'
GROUP BY p.id
HAVING
-- Ensure there's no direct denial overriding the permission
MAX(CASE WHEN mp_direct.allowed IS NOT NULL THEN mp_direct.allowed ELSE TRUE END)