Files
leaudit-platform-backend/docs/权限与地区隔离/租户与角色权限关系真实案例说明.md

251 lines
5.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 租户与角色权限关系真实案例说明
> 适用范围:`leaudit-platform` 当前 `角色权限 + 租户配置 + 数据范围` 模型
> 更新日期:2026-05-20
> 文档定位:不用抽象术语,直接用真实业务例子说明“租户”和“角色权限配置”到底是什么关系。
---
## 1. 先记一句最核心的话
这套系统里有三层控制:
1. `角色权限`
- 管“这个人能不能做这件事”
2. `租户配置`
- 管“这件事能不能落到这个租户上”
3. `数据范围`
- 管“这个人最终能看到哪些租户的数据”
它们是三层,不是一层。
---
## 2. 例子 1:入口模块
假设现在有两个租户:
- `MZ` = 梅州
- `PUBLIC` = 公共资源域
再假设有一个用户 `张三`
- 人属于 `MZ`
- 角色有:
- `entry_module:create`
- `entry_module:update`
这时候只能说明一件事:
- 张三“有权新建和编辑入口模块”
但这还不能直接推出:
- 张三可以把入口模块挂到任何租户上
还要再看租户配置。
如果租户配置是:
- `MZ.feature_keys` 包含 `home.entry_module`
- `MZ.can_host_entry_module = true`
- `PUBLIC.feature_keys` 包含 `home.entry_module`
- `PUBLIC.can_host_entry_module = false`
那么结果就是:
1. 张三可以进入入口模块管理页
2. 张三可以新建入口模块
3. 张三可以把模块挂到 `MZ`
4. 张三不能把模块挂到 `PUBLIC`
为什么?
- 因为权限页只给了他“操作资格”
-`PUBLIC` 没开放“可承载入口模块”
所以这里的判断链路是:
1. 先看角色权限:能不能新建
2. 再看租户承载能力:这个租户能不能被选
3. 最后才允许落库
---
## 3. 例子 2:文档上传
假设用户 `李四`
- 属于 `HZ`
- 角色里有 `documents:upload:create`
这说明:
- 李四“可以上传文档”
但如果 `HZ` 这个租户配置是:
- `feature_keys` 没有 `documents.upload`
- 或者 `can_host_documents = false`
那么正确行为应该是:
1. 李四即使有上传权限
2. `HZ` 这个租户也不应该作为文档归属租户被使用
3. 页面可能不显示上传入口,或者后端直接拒绝
也就是说:
- `有权限` 不等于 `这个租户允许承载这类业务`
---
## 4. 例子 3:知识库
假设用户 `王五`
- 属于 `MZ`
- 角色里有 `rag:dataset:manage`
这说明:
- 王五可以管理知识库
但是否能给 `SZ` 租户建知识库,还要看:
- `SZ.feature_keys` 是否开启了 `rag.dataset`
- `SZ.can_host_rag` 是否为 `true`
如果:
- `SZ` 没开 `rag.dataset`
那就算王五权限再高,也不应该把知识库业务落到 `SZ`
这里要理解:
- `rag:dataset:manage` 是“人有能力操作”
- `feature_keys / can_host_rag` 是“租户有没有资格承载这个业务”
---
## 5. 例子 4:公共资源域 `PUBLIC`
这个最容易混。
假设 `PUBLIC` 用来放:
- 公共模板
- 公共规则
- 公共知识库底座
- 公共入口模块
`PUBLIC` 的意义是:
- 这是一个“共享资源归属地”
- 不是谁都能随便改的地方
比如用户 `赵六`
- 属于 `MZ`
- 角色只有 `document:read`
那他可能可以看到 `PUBLIC` 下的一些共享资源,
但如果没有 `document:update` 或更高权限:
- 他也不能改 `PUBLIC` 的资源
所以:
- `PUBLIC` 决定资源归属偏共享
- `角色权限` 决定你能不能动这份共享资源
---
## 6. 例子 5:为什么角色权限页和租户页看起来都在管“入口模块/文档/知识库”
因为它们问的不是同一个问题。
角色权限页在问:
- 这个用户能不能进入这个模块?
- 能不能新增、编辑、删除?
租户页在问:
- 这个租户开不开这个业务?
- 这个租户能不能承载这类数据?
可以把它理解成:
- `角色权限 = 驾照`
- `租户能力 = 哪些路允许走`
- `数据范围 = 你今天实际能开到哪些区域`
只有驾照,没有开通道路,不行。
只有道路开放,没有驾照,也不行。
---
## 7. 一个完整串联例子
假设你要“给梅州上线一个新的首页入口模块”。
要同时满足下面 6 件事:
1. 当前操作人有权限
- 例如有 `entry_module:create`
2. `MZ` 租户开放了入口模块业务
- `feature_keys` 包含 `home.entry_module`
3. `MZ` 允许承载入口模块
- `can_host_entry_module = true`
4. 当前人数据范围允许操作这个租户
- 不是只能管自己部门,却跑去配别的租户
5. 首页用户属于 `MZ`
- 登录后解析出 `tenant_code = MZ`
6. 首页读取时,模块租户关系里包含 `MZ`
最后结果才是:
- 后台能配置
- 前台能看到
- 数据不会挂错租户
---
## 8. 一句话收口
比如“入口模块”这个词,在系统里其实对应 3 个不同问题:
1. `角色权限`
- 你能不能配入口模块
2. `租户配置`
- 这个租户开不开入口模块
- 这个租户能不能承载入口模块
3. `数据范围`
- 你能不能看到或操作这个租户下的入口模块
这三件事少一件都不成立。
---
## 9. 最终理解公式
后续看所有业务模块,都可以套下面这条公式:
`最终是否允许 = 角色权限通过`
并且
`目标租户开放该业务`
并且
`目标租户允许承载该类数据`
并且
`当前用户数据范围允许访问该租户/该资源`
只要按这个公式看,就不会再把“角色权限”和“租户配置”混成一件事。