从原理到源码解析数据权限控制
在常规开发中,权限控制通常聚焦于两点:
- 前端组件显示:控制菜单、按钮的可见性;
- 后端接口访问:控制用户能否调用指定 URL。
但这两种权限控制的核心局限在于:它们管控的是不同的对象(如组件 A 与组件 B、接口 A 与接口 B),无法解决同一对象内的数据隔离问题。
实际业务中存在这类痛点:所有用户数据存储在同一张表中,要求不同部门的用户只能查看本部门数据。此时,同一查询接口、同一条 SQL,需要根据用户身份返回不同结果,而菜单权限无法实现这一需求,因此数据权限的引入成为必然。
一、问题引入:为什么需要数据权限?
在常规开发中,我们对权限的控制通常体现在两个方面 :
前端组件显示:控制菜单或按钮的显隐 。
后端接口访问:控制用户是否有权请求某个 URL 。
但这两种方式有一个共同特点:它们针对的往往不是同一个对象(比如组件 A 和组件 B,接口 A 和接口 B)。
现在的痛点是: 我们要针对同一个对象(例如“用户表”里的数据)进行控制 。假设所有用户数据都存在同一张表中,需求是:不同部门的用户只能看到自己部门的数据 。
如果仅仅使用菜单权限,无法解决“同一个接口(list)、同一个 SQL,却要返回不同结果”的问题。这就需要引入数据权限。
二、 解决方案与现象展示
RuoYi 框架通过在“角色管理”中配置“数据范围”来解决这个问题。
1.配置数据权限
管理员进入【系统管理 -> 角色管理】,可以为角色分配不同的数据权限范围 :
2. 实际效果
假设我们有两个用户:
admin(超级管理员):拥有全部数据权限 。
ry(普通角色):隶属于测试部门,仅拥有本部门数据权限 。
当他们分别访问同一个【用户管理】页面时:
admin 能看到研发部门、测试部门等所有公司的用户数据 。
ry 只能看到测试部门的 1 条数据,其他数据被自动过滤 。
数据权限的本质,其实就是修改 SQL 语句 。RuoYi 利用 AOP(面向切面编程)和 MyBatis 的动态 SQL 能力,实现了这一过程的自动化。
3.后端源码分析
第1步:Controller 发起请求
第2步:进入 Service 实现类
第3步:AOP 切面拦截(核心!)
当调用带有 @DataScope 注解的方法时,DataScopeAspect.java 会拦截:
第4步:handleDataScope 方法处理
第5步:dataScopeFilter 生成SQL条件
第6步:进入 Mapper 执行SQL
第7步:XML 中的 SQL 拼接
总结流程图
总结
RuoYi 的数据权限实现是 AOP + 动态 SQL 的经典应用。
作用:限制同一类型数据的不同行 。
操作:给角色配置数据权限,给用户分配角色 。
原理:
Service 层使用 @DataScope 定义别名 。
Aspect 层根据注解和用户信息,动态生成 SQL 过滤片段 。
Mapper 层通过 ${params.dataScope} 将过滤条件注入 SQL 。
通过这种方式,我们不仅实现了灵活的权限控制,还将权限逻辑与业务逻辑彻底解耦,极大地提高了代码的可维护性。
车间的设备数据设计数据权限
(1).创建设备实体类 Equipment.java
(2).创建设备Mapper接口 IEquipmentMapper.java
(3).创建设备Mapper XML配置文件
(4).创建设备Service接口 IEquipmentService.java
(5).创建设备Service实现类 EquipmentServiceImpl.java
(6).创建设备Controller控制器
(7).创建数据库建表SQL脚本
演示
分配菜单权限和数据权限给普通角色
超级用户赋予普通用户一定的权限,安装位置数据没给授权,那么ry用户哪里就不会显示
如果超级用户没给予车间权限,ry用户不会显示
