外观
权限与数据范围
字数
4414 字
预计阅读
17 分钟
权限分两层:
- 功能权限:能不能做某件事,比如"新增用户"、"导出图书"。按菜单和按钮授权;
- 数据范围:能看到、能改哪些数据,比如"只看本部门的用户"。按部门授权。
两层都由服务端检查。界面上隐藏按钮只是为了好用,就算有人绕过界面直接调用接口,也会被服务端拦下来。
两层都配置在角色上:管理员给角色授权,再把角色分配给用户。
功能权限
权限点
权限点是一项具体操作的编码,格式是 域.资源.动作,比如 iam.user.create 表示"新增用户"。菜单里的每个按钮对应一个权限点。
常见的动作:
| 动作 | 按钮名称 | 作用 |
|---|---|---|
browse | 浏览 | 打开列表 |
view | 查看 | 看详情,打开编辑弹框也需要它 |
create | 新增 | |
modify | 修改 | 包括启用、停用 |
remove | 删除 | 包括批量删除 |
export | 导出 | 导出 Excel |
import | 导入 | 导入 Excel |
有些模块还有自己的动作,比如用户管理的"重置密码"(iam.user.reset-password)、角色管理的"授权"(iam.role.grant)。
给角色授权
在 系统管理 → 角色管理 中,点角色那一行的 更多 → 菜单权限:
- 弹框里是所有菜单组成的一棵树,按钮旁边显示它的权限点;
- 停用的菜单也会显示(带"停用"标签),可以勾选,但停用期间它不授予任何权限;
- 父子联动开启时,勾选下级会带上上级,勾选上级会带上全部下级。需要精确控制时可以关掉;
- 只勾了某个按钮时,它所在的页面和目录也会出现在侧边栏里。
把角色分给用户
有三个地方可以分配:
- 系统管理 → 用户管理:新增或编辑用户时直接选角色;
- 系统管理 → 用户管理 → 更多 → 分配角色;
- 系统管理 → 角色管理 → 更多 → 分配用户:一次给多个用户分配,或者取消分配。
用户最终有哪些权限
用户的权限 = 他的已启用角色所授权的、已启用菜单上的权限点合在一起。
- 角色停用后,它的权限立即失效;
- 菜单(或者它的任何一级上级目录)停用后,它下面的按钮都不再授予权限,页面也从侧边栏消失。
没有权限时:
| 地方 | 表现 |
|---|---|
| 按钮 | 不显示 |
| 侧边栏 | 没有这个页面 |
| 在地址栏直接输入页面地址 | 显示 404 页面 |
| 直接调用接口 | 返回 403,提示"没有执行此操作的权限" |
权限何时生效
修改以下内容后,对方不需要重新登录。他的下一次请求会发现权限变了,服务端重新加载他的权限,界面上的菜单和按钮也自动更新:
- 角色的菜单权限、数据权限、启用状态;
- 用户的角色、所在部门;
- 菜单管理中的任何修改;
- 调整部门的上下级。
停用或删除用户时,他的所有登录会立即失效。
新模块不会自动授权
用代码生成器新建的页面,只有超级管理员能马上看到。其他人要在角色管理里勾选后才能使用,见新增业务模块。
数据范围
功能权限决定"能不能浏览用户",数据范围决定"浏览时能看到哪些用户"。
在 系统管理 → 角色管理 中,点 更多 → 数据权限 设置。有五种:
| 数据范围 | 编码 | 能看到的数据 |
|---|---|---|
| 全部数据 | all | 所有数据 |
| 指定部门 | picked_depts | 在下面的部门树里勾选的部门 |
| 本部门 | own_dept | 用户自己所在部门 |
| 本部门及下级 | own_dept_tree | 用户所在部门,以及它下面的所有部门 |
| 仅本人 | own_rows | 用户自己创建的数据 |
- 新建的角色,数据范围默认是"本部门";
- 选"指定部门"时,部门树只显示你自己能看到的部门。角色原来选过、但你看不到的部门,弹框会提示有几个,保存时保持不变;
- 用户没有所属部门时,"本部门"和"本部门及下级"都看不到任何数据。
哪些地方受数据范围限制
| 页面 | 按什么判断 | "仅本人"时 |
|---|---|---|
| 系统管理 → 用户管理 | 用户所在部门 | 只看到自己 |
| 系统管理 → 部门管理 | 部门本身 | 看不到任何部门 |
| 系统监控 → 在线用户 | 登录用户所在部门 | 只看到自己的登录 |
| 流程审批 → 流程管理 的实例管理、任务管理、审批数据,以及管理员查看审批详情 | 发起部门(发起申请时发起人所在的部门,之后调动部门也不变) | 只看到自己发起的 |
| 生成示例 → 图书 | 图书的所属部门 | 自己创建的图书 |
| 代码生成器生成的、带部门列的模块 | 记录的所属部门 | 自己创建的记录 |
后台页面里选择用户的弹框、选择部门的下拉树,默认也只列出范围内的用户和部门(审批表单里的"人员选择"、"部门选择"不受限制,见表单设计器)。
角色管理不受数据范围限制:角色不属于任何部门,谁能管角色只看有没有 iam.role.* 权限。由此带来的风险,由下面的防越权授予兜底。
用户有多个角色时
一个角色只有给了你这项权限,它的数据范围才算数。 符合条件的角色有好几个时,它们的范围合在一起(并集)。不需要权限的地方(选择用户的弹框、选择部门的下拉树)按你所有已启用角色的范围合在一起算。
举个例子,张三有两个角色:
| 角色 | 有"用户管理 → 浏览"吗 | 数据范围 |
|---|---|---|
| 人事专员 | 有 | 本部门 |
| 报表查看 | 没有 | 全部数据 |
张三浏览用户时,只按"人事专员"算,只能看到本部门的用户。"报表查看"的"全部数据"不算数,因为这个角色并没有让他浏览用户。
这样,给某人加一个"范围很大、但权限很少"的角色,不会意外扩大他其他操作的范围。
超出范围时
- 列表、导出、下拉选项里,不包含范围外的数据;
- 打开、修改、删除范围外的某一条数据,返回 404,提示"请求的资源不存在",和数据真的不存在时一模一样;
- 批量操作中只要有一条超出范围,整个请求失败,一条都不会修改;
- 新增或修改后,这条数据必须仍在你的范围内,否则返回 404。比如"本部门"的角色把所属部门改成别的部门,会保存失败。"仅本人"不看所属部门:在图书和代码生成的模块里,自己创建的记录填哪个所属部门都能保存;在用户管理里,"仅本人"只能修改自己,新增用户一定返回 404。没有填所属部门时,只有"全部数据"或"仅本人"的角色能保存(用户管理除外);
- Excel 导入选"新增并更新已有记录"时,只会匹配范围内的记录。范围外有相同唯一值的记录时(比如图书的 ISBN 相同),这一行按"数据已存在"报错,不会覆盖它。
为什么是 404 而不是 403
返回 403 等于告诉对方"这条记录存在,只是你没有权限"。统一返回 404,就不会泄露记录是否存在。
防越权授予
能管理角色和用户的人,不能把超过自己的权限交给别人,也不能交给自己。否则"我能管角色,就给自己建一个超级角色"就成了可能。
这些规则对超级管理员以外的所有人生效,违反时返回 403,提示"不能授予超出自己权限或数据范围的角色":
- 菜单权限:给角色新勾选的按钮,自己必须也有。另外,这个角色的数据范围不能比你在这项权限上的范围大:不能借一个范围更大的角色,把"同样的权限"送到你管不到的部门。数据范围是"全部数据"的角色,不能从你这里获得任何权限;
- 数据权限:不能设为"全部数据"(下拉框里也不会出现这一项);新增覆盖的部门,必须在你自己的范围内,并且对这个角色的每一项权限分别检查。缩小范围不检查;
- 分配角色(新增和编辑用户、分配角色、分配用户):
- 不能分配超级管理员角色,也不能分配"全部数据"的角色;
- 角色上的所有权限点(包括停用菜单上的)自己都要有;
- 角色覆盖的部门要在自己的范围内。"本部门"类的角色按接收角色的那个用户的部门计算;
- 把用户调到别的部门时,他已有的"本部门"类角色会跟着变,所以也要重新检查。
- 间接授予也一样检查:
- 在 系统管理 → 菜单管理 中给菜单填写权限点时,只能填自己有的;
- 修改菜单(改权限点、启用菜单或它的上级目录、把菜单移出停用的目录)让某些角色新得到了权限点,按第 1 条检查;
- 重新启用一个停用的角色,等于把它的全部权限再交出去一次,按第 1、2 条检查(停用不检查)。
只检查新增的部分。保留或者取消已有的授权,不会让别人得到更多,所以总是允许。
例子:让部门经理查看审批数据
功能权限、数据范围和业务自己的规则是叠加起作用的。以审批数据为例:
- 在 系统管理 → 角色管理 里,给"部门经理"角色打开 更多 → 菜单权限,在 流程审批 → 流程管理 → 审批数据 下勾选"浏览"(
wf.data.browse),需要导出再勾"导出"(wf.data.export); - 他能看到哪些申请,由这个角色的数据权限决定,按发起部门(发起申请时发起人所在的部门)计算。比如设为"本部门及下级",他就只看到在这些部门发起的申请;
- 如果他还有别的角色,那些角色没有
wf.data.browse的话,它们的范围在这里不算数(见用户有多个角色时); - 做这个授权的人如果不是超级管理员,自己也要有这两个权限,并且"部门经理"角色的范围不能超出他自己在这两个权限上的范围(见防越权授予);
- 他看不到流程里任何节点设为"隐藏"的字段,页面顶部会提示有几个字段被隐藏。需要看薪资这类敏感字段的人(比如 HR),在 流程审批 → 流程管理 → 模型管理 里编辑这个审批,把他加进"流程管理员",他就能看到并导出全部字段。修改流程管理员需要 模型管理 下的"任命流程管理员"权限(
wf.model.managers),默认只有超级管理员有;没有这个权限的人,"流程管理员"这一项是只读的。超级管理员始终能看到全部字段。详见工作流 · 审批数据里的字段权限。
超级管理员
内置角色"超级管理员"(编码 root)拥有全部权限,不受数据范围限制,也不受防越权授予的限制。初始化时创建的 admin 用户就是超级管理员。
一个用户是不是超级管理员,只看他有没有这个内置角色。自己新建的角色,勾选的菜单再多,也不是超级管理员。
受保护的角色和账号
| 对象 | 保护规则 |
|---|---|
| 超级管理员角色 | 不能删除、不能停用、不能改编码;它本来就有全部权限,所以不能设置菜单权限和数据权限;只有超级管理员能编辑它 |
| 超级管理员角色的分配 | 别人在选择角色时看不到它,也分配不了;任何人都不能把它从用户身上取消 |
| 有这个角色的用户 | 任何人都不能删除或停用他;不是超级管理员的人不能编辑他、重置他的密码、修改他的角色,也不能强退他 |
| 自己的账号 | 不能删除或停用自己 |
违反时提示"内置角色受保护,不能执行此操作"或"超级管理员账号受保护,不能执行此操作"。
另外,被用户占用的角色不能删除,提示"角色已分配给用户,请先取消分配再删除"。
只有超级管理员能做的事
| 事情 | 原因 |
|---|---|
修改注册相关的参数:auth.signup.enabled(是否开放注册)、auth.signup.default_role_id(注册默认角色)、auth.signup.default_dept_id(注册默认部门) | 决定陌生人注册后得到什么权限 |
| 修改注册默认角色本身、它的菜单权限和数据权限,以及在 系统管理 → 角色管理 → 更多 → 分配用户 里为它增减成员(在用户管理里给用户分配或取消这个角色不受此限制,只按防越权授予检查) | 同上 |
修改 auth.wx_mp.enabled(微信小程序登录开关) | 决定能不能用微信登录 |
新增、修改、删除、测试发送编码以 auth. 开头的短信模板;修改、删除这些模板使用的短信渠道 | 登录和找回密码的验证码走这条路,改了就可能让验证码经过别人的短信账号发出 |
| 在角色的数据权限里选"全部数据" | 见防越权授予 |
其他人做这些事时返回 403。
日常管理不要用超级管理员
超级管理员不受任何限制,出了问题影响最大。建议只用它做初始配置,日常的管理工作交给普通角色,按需要授予权限和数据范围。
开发指南
- 在代码中使用权限与数据范围:权限常量、保护接口、给实体加数据范围、按 id 修改的写法
- 权限与翻译:前端按权限显示按钮
- 种子与菜单:在种子里添加菜单和按钮权限
- 服务 · 按 id 修改的标准写法
- 路由与菜单:菜单怎么变成前端路由
相关功能:
- 安全基线
- 工作流 · 审批数据
- 代码生成器:带部门列的表会自动接入数据范围