Mybatis DataPermissionInterceptor实现数据权限详解
📌 Mybatis DataPermissionInterceptor实现数据权限详解
1️⃣ 问题背景
在RBAC权限模型中,角色可以控制菜单、按钮、接口访问权限,但很多场景下仅有功能权限远远不够。
例如:
- 校长可以查看全校学生信息
- 院长只能查看本学院学生信息
- 辅导员只能查看自己管理班级学生信息
- 教师只能查看自己授课班级学生信息
- 销售经理可以查看部门所有客户
- 普通销售只能查看自己的客户
如果没有数据权限,那么拥有查询接口权限的用户可能看到全部数据,造成严重的信息泄露问题。
2️⃣ 核心原理
Mybatis提供了Interceptor插件机制,可以拦截Executor、StatementHandler、ParameterHandler、ResultSetHandler等核心组件。
数据权限最常见的实现方式就是拦截SQL执行过程,在SQL发送到数据库之前动态追加权限条件。
↓
进入Controller
↓
进入Service
↓
调用Mapper
↓
DataPermissionInterceptor拦截SQL
↓
追加权限条件
↓
执行数据库查询
↓
返回符合权限的数据
例如原始SQL:
经过数据权限拦截后:
数据库最终只返回当前用户有权限查看的数据。
3️⃣ 数据结构分析
用户表
id
username
dept_id
角色表
id
role_name
data_scope
角色数据权限字段
data_scope通常定义以下几种权限:
- ALL:全部数据权限
- DEPT:本部门数据
- DEPT_AND_CHILD:本部门及子部门
- SELF:本人数据
- CUSTOM:自定义数据权限
例如:
院长 → DEPT
教师 → SELF
4️⃣ 算法分析
DataPermissionInterceptor本质上就是SQL改写算法。
核心流程如下:
↓
获取用户角色
↓
获取数据权限范围
↓
解析原始SQL
↓
拼接权限条件
↓
替换BoundSql中的SQL
↓
继续执行
例如:
select * from student where status=1
当前用户属于计算机学院:
拼接后:
where status=1
and college_id=1001
5️⃣ 执行流程
第一步:定义数据权限注解
@Retention(RetentionPolicy.RUNTIME)
public @interface DataPermission {
String value();
}
Mapper方法增加注解:
List<Student> selectList();
第二步:定义拦截器
@Signature(
type=StatementHandler.class,
method="prepare",
args={Connection.class,Integer.class}
)})
public class DataPermissionInterceptor
implements Interceptor{ }
第三步:获取当前SQL
statementHandler.getBoundSql();
String sql = boundSql.getSql();
第四步:获取用户信息
SecurityContextHolder.getUser();
第五步:拼接权限SQL
loginUser.getDeptId();
第六步:替换SQL
SystemMetaObject.forObject(statementHandler);
metaObject.setValue(
"delegate.boundSql.sql",
newSql
);
至此完成SQL动态改写。
6️⃣ 实际案例
案例一:教师查看学生
原SQL:
当前教师ID:
改写后:
where teacher_id=10086
案例二:部门经理查看员工
部门ID:
改写后:
where dept_id=20
案例三:集团管理员
管理员拥有ALL权限。
此时不需要拼接任何SQL。
直接执行即可。
7️⃣ 优缺点分析
优点
- 业务代码零侵入
- 统一权限控制
- 开发成本低
- 扩展性强
- 适合大型管理系统
- 支持RBAC权限体系
- 支持多租户扩展
缺点
- SQL解析复杂
- 多表关联处理麻烦
- 动态SQL容易出错
- 性能有一定损耗
- 复杂查询维护成本较高
8️⃣ 面试常见问题
面试题1:为什么选择Mybatis拦截器实现数据权限?
因为可以在SQL执行前统一修改SQL,实现业务无侵入的数据权限控制。
面试题2:拦截器拦截哪个对象?
通常拦截StatementHandler.prepare方法,因为此时SQL已经生成但尚未发送数据库。
面试题3:为什么很多框架使用JSqlParser?
直接字符串拼接容易导致SQL错误,JSqlParser可以将SQL解析为语法树,安全地增加Where条件。
面试题4:若SQL已经有Where怎么办?
需要判断SQL结构,如果存在Where则追加AND,否则新增Where。
面试题5:若存在多表关联怎么办?
需要指定数据权限字段所属表别名,例如:
from student s
left join class c
on s.class_id=c.id
and s.dept_id=10
面试题6:若使用Spring Security如何获取用户?
通常从SecurityContextHolder获取当前登录用户信息。
面试题7:若管理员拥有全部权限怎么办?
直接跳过SQL改写逻辑即可。
面试题8:Mybatis-Plus如何实现数据权限?
Mybatis-Plus提供DataPermissionInterceptor,可以结合JSqlParser自动完成SQL权限拼接。
9️⃣ 总结
📌 Mybatis数据权限的核心思想是在SQL执行前动态改写SQL。
📌 DataPermissionInterceptor本质是Mybatis插件机制的应用。
📌 拦截StatementHandler获取原始SQL,根据当前用户角色生成权限条件。
📌 将权限条件动态追加到Where子句,实现行级数据隔离。
📌 企业级项目通常采用“RBAC + 数据权限 + Mybatis拦截器 + JSqlParser”方案,实现统一的数据权限控制体系。
🚀 面试中如果能够讲清楚Interceptor拦截原理、BoundSql修改流程、JSqlParser解析机制以及Mybatis-Plus DataPermissionInterceptor实现原理,基本可以覆盖绝大多数中高级Java岗位的数据权限相关问题。
上一篇:无
相关文章
-
Mybatis DataPermissionInterceptor实现数据权限详解
面试中如果能够讲清楚Interceptor拦截原理、BoundSql修改流程、JSqlParser解析机制以及Mybatis-Plus DataPermissionInterceptor实现原理,基本可以覆盖绝大多数中高级Java岗位的数据权限相关问题。
NEW个对象 2026-06-14