前言
资源是一个抽象概念,包括系统所需要控制的所有对象,例如文件、菜单、按钮、任务等等,本章以最常用的菜单、按钮作为代表!
角色是权限设计的核心,用来控制资源的权限,角色也是数据权限的"阀门"。本章详细讨论角色的设计及资源设计。
角色设计
按照惯例,我们从属性、功能、关联关系三个维度考虑角色设计:
- 属性 大概包括角色名称、备注信息、ID、状态等
- 功能 设置用户、分配资源权限、刷新权限等
- 关联关系 关联用户、关联资源等
经过思考梳理后,形成以下花型图:

通过花型图,总结如下:
- 属性中 绿色 部分为角色对应的业务属性,蓝色部分为审计属性
- 功能中 橙色 部分为管理功能,红色 部分为状态相关,蓝色部分为关联关系功能
为了权限设计的简洁,我们不考虑角色互斥条件。互斥功能,随着业务复杂性的提高,会导致权限管理的混乱!角色继承是默认的条件,比如用户只能分配拥有的资源权限,避免造成权限窃取 及泄露!
角色属性
角色在设计上相对简单,主要包括以下属性:
- ID 没有实际意义,用来适配框架(通用的增删改查操作)
- 角色名称 一般用来标记业务相关的名称
- 是否默认 用于处理人员直接分配资源权限(离散型权限)
- 状态 角色的状态管理,生效、失效等功能
- 备注 角色的备注说明信息
- 审计属性前面章节已详细说明,此处不再赘述
某些业务场景下,资源权限比较分散,且互不重叠,即离散型权限:比如A用户需要X资源权限,B用户需要Y权限,此时建立角色反而冗余,可以直接对用户分配权限,为了权限的统一处理,此时我们针对每个用户创建一个默认角色进行处理
角色功能
角色主要包含以下功能:
- 新增 新添加一个角色,必填字段角色名称
- 修改 修改角色名称及备注信息
- 删除 删除角色,该功能有一定的风险,删除后权限会失效
- 查询 角色状态及名称查询
- 明细 查看角色的详细信息
- 刷新权限 分配资源权限后刷新缓存信息,使权限生效
- 资源权限 分配菜单按钮资源权限
- 添加用户 角色关联多个用户信息,从角色维度中进行用户关联
- 停用 停用角色,使之数据权限失效
- 启用 启用停用的角色
为提高效率在项目启动时会将资源及角色信息进行缓存(功能设计章节中描述过),分配完资源权限后需要刷新缓存使之生效(功能数量少时可将该功能集成到分配资源权限功能中)。
每一个功能都是由URL+Method进行唯一标识,角色分配资源后,用户访问该功能,通过URL+Method定位到按钮后到缓存查询对应的角色,从用户角色列表中查看是否包含该角色,从而完成鉴权,具体请查看前面的功能设计章节。
资源设计
资源包括菜单和按钮,都通过URL+Method进行访问。菜单中包含按钮,按钮又称为功能,每个功能可以定义数据权限,所以对于按钮而言即包括资源权限定义又包含数据权限关联。
同样通过功能、属性和关联关系维度来梳理下资源设计,经过整理具体如下:

从花型图上菜单和按钮拥有共同的资源属性,具体为:
- ID 无实际意义,仅满足框架的通用操作
- 资源ID 对应菜单或按钮的ID
- 资源类型 菜单或按钮标识
- 请求URL 请求该资源的URL 例如/api/user/search
- 请求方法 请求该资源的请求方法 例如 POST
在资源设计中URL+Method为资源的唯一索引。通过资源的抽象,在系统中通过RequestContext(请求封装)获取请求的URL及方法就可以进行资源的查询定位,从而进行权限的相关操作。
菜单设计

菜单属性
在权限系统中,菜单是按钮的集合,菜单作为功能的"门户"也是资源权限的第一道"阀门",主要包含如下属性:
- ID 菜单资源的ID,用来标识该资源
- 菜单名称 菜单的名称,例如用户管理、角色管理等
- 父菜单ID 菜单是一个树结构,有父菜单,如果是跟菜单则父菜单ID为空
- 菜单类型 通过类型来区分不同类型的菜单,例如业务型、管理型等,权限系统只加载管理类型菜单
- 图标 主要适配前端显示
- 优先级 同级菜单优先级低的排列在前
- 是否隐藏 隐藏后不显示
- 是否忽略权限 设置后不再进行权限过滤
- 审计属性不再赘述
菜单功能
菜单是一个属性结构,拥有子菜单及跟菜单的功能,具体如下:
- 查询 根据菜单名称查询菜单
- 明细 查看菜单的详细信息
- 新增子菜单 菜单中添加子节点,建议最多三级菜单
- 新增根菜单 作为单独的功能,方便根节点对应的父节点拥有特殊的定制值
- 修改 通过修改属性中的忽略授权 和是否隐藏达到对应的功能
菜单在权限系统中根据用户角色进行资源验证并加载,设置忽略权限后,该菜单总是会加载。菜单是在用户登录后进行加载,明确用户是基础(需要明确用户的角色)。系统不对无登录菜单进行管理。
按钮设计
按钮也就是功能,是系统授权的核心,同时拥有资源权限和数据权限,资源权限用于表示能否操作,数据权限表示操作那些数据!

按钮属性
每个按钮都关联到菜单,我们设置权限时通过选择菜单展示对应的按钮,进行按钮的权限设置。隐藏的菜单不影响按钮权限的校验。按钮的具体属性如下:
- ID 按钮资源的ID,全局唯一,格式为菜单ID:按钮功能,例如user:search 表示用户查询按钮
- 按钮名称 用于表示功能的简要名称
- 菜单ID 关联的菜单ID
- 子标题 用于在资源权限设置中分组,例如 按照功能类型分组,在具体菜单下分为 读取相关 写入相关等
- 是否忽略授权 忽略授权后,不对该按钮进行角色授权的验证,只要登录就能看到该按钮
- 是否忽略鉴权 勾选忽略授权后才可以勾选该功能,设置后不需要登录即可看到该按钮
- 备注 按钮的说明信息
鉴权和授权只是资源权限关联的功能,不影响数据权限的功能,例如用户查询功能,可以不登录就能看到,但能查询哪些数据是数据权限决定的。 子标题在自定义权限分组时尤其有用,面对复杂的业务系统,可以根据业务的需要来定义分组,更便于业务资源权限的管理。
按钮功能
按钮的功能除了自身的基础功能外还包含设置数据权限对应的功能,具体如下:
- 新增 新增加一个按钮,必须关联菜单
- 复制新增 复制一个已有的按钮修改对应的信息,创建新按钮
- 删除 删除按钮,对应的资源权限和数据权限都将失效
- 查询 按照名称查询按钮
- 明细 查看按钮的明细信息
- 修改 修改按钮的信息,包括按钮的基础信息、资源权限信息、数据权限信息
按钮资源权限信息包括忽略授权和忽略鉴权,数据权限信息包括权限标识和权限引用,设置权限标识代表需要为该按钮配置数据权限,默认情况下只能查看自己(创建人是当前用户)的数据.
数据权限

数据权限是一个单独的数据结构定义,具体包含如下属性:
- ID 没有实际意义,用于服务框架的通用增删改查
- 权限名称 权限的对应名称 一般与按钮名称一致
- 菜单ID 按钮对应的菜单ID
- 按钮ID 按钮的ID
- 请求方法 该按钮对应的请求方法
- 请求URL 该按钮对应的请求URL
- 权限动作 表示数据权限的标识,也称Action,在数据权限配置时使用该权限动作,唯一
- 权限引用 用来表达同样的数据权限,方便复用,值为对应的权限动作值
请求URL和请求方法是针对WEB系统的设计,在查找数据权限定义时通过请求URL+请求方法来定位数据权限,这是用户驱动(用户在界面点击按钮)的情况,有时需要内部系统的驱动,就需要通过权限动作来定位数据权限。
委托
数据权限的设置是基于资源权限的基础上设置,即先拥有资源数据权限才能配置数据权限
按钮与数据权限定义是一对一的关系,Action是数据权限的唯一标识,通过Action来定位数据权限后,就可以匹配用户相关的委托,具体包含:
- 用户委托 通过用户直接进行委托
- 用户组委托 通过用户组进行委托,用户组内的用户都拥有对应的委托
- 职位委托 通过职位进行委托,具体查看《权限系统设计-职位设计》章节,职位对应的用户都拥有该委托,注意职位委托不区分功能,针对所有功能
委托是数据权限的一个概念(作者根据自己的理解起的名字),简述为:能看到那些用户的数据,比如看到张三的数据,可描述为:委托张三,也称为人员委托 ;如果能看到整个部门所有人的数据,则委托部门ID,也称为组织委托 系统根据委托信息来进行SQL拼接,从而达到数据权限过滤的目的。
具体如下:

数据权限的配置最终体现在对应的用户上,体现在用户在某个功能上能看到哪些数据或操作哪些数据!
从图上我们总结为:
- 角色是数据权限过滤的第一道阀门,没有角色授权,就没有数据权限设置
- 数据权限有三个维度的设置:用户维度、用户组维度及职位维度,用户维度和用户组维度可针对特定的功能
- 数据权限设置分为三个维度:功能数据权限,通过委托的维度设置权限,即用户能看到哪些委托的数据;业务数据权限,通过解析SQL后列出对应的表和列信息,可通过条件构造器自定义配置表列对应的条件,从而达到灵活构建数据权限的目的;列数据权限,该数据权限只针对SELECT查询,通过不允许哪些列达到过滤列权限的目的。
一个简单的配置例子为:
java
@Action(value = "ORDER_SEARCH")
@ActionConnect(value = {"selectList","selectCount"})
- @Action表示权限动作,其值为ORDER_SEARCH
- @ActionConnect为权限链接,表示数据权限作用于那个mapper(Mybatis的Mapper)
通过此配置后,执行方法会拦截获取对应的权限动作,通过获取的当前用户信息,权限动作查找用户委托、用户组委托、职位委托,汇总委托信息后进行存储,通过配置的用户委托列(默认为创建人)、组织委托列(默认为组织ID)来构建委托SQL,同时根据配置的业务数据权限来构建业务权限SQL,根据配置的列数据权限来构建排除列SQL,最终汇总成需要追加的SQL。
@Action和@ActionConnect还有更详细的配置,比如不同的用户针对不同的表列字段,有些用户需要忽略分公司权限,有些用户只过滤分公司权限;有些用户 这个有些又可以通过用户的自定义Tag来进行定义,更详细信息在后续数据权限章节详述。
总结
本章我们详细讲述了角色资源的设计,其中包括部分的数据权限设计,有什么问题再评论区留言一起探讨吧!