数据权限规则
Forge 通过 DataScopeInterceptor 实现行级数据权限控制。你需要理解它与 @SaCheckPermission 的区别,以及 Mapper XML 的正确写法。
数据权限 vs 功能权限
| 维度 | 功能权限 | 数据权限 |
|---|---|---|
| 注解 | @SaCheckPermission | DataScopeInterceptor |
| 控制粒度 | 接口能否访问 | 能看到哪些数据行 |
| 作用层 | Controller | Mapper SQL 改写 |
| 场景 | 用户有没有"删除"按钮 | 用户只能看本部门数据 |
java
// 功能权限:控制接口能否访问
@SaCheckPermission("system:user:list")
@GetMapping("/page")
public RespInfo page() { ... }
// 数据权限:控制返回哪些行(DataScopeInterceptor 自动改写 SQL)
// 无需注解,拦截器按 mapperMethod 匹配自动改写DataScopeInterceptor 工作原理
拦截器按 mapperMethod(Mapper 接口全限定名 + 方法名)精确匹配,找到匹配规则后改写 SQL:
sql
-- 原始 SQL
SELECT u.* FROM sys_user u WHERE u.del_flag = 0
-- 改写后(根据当前用户的数据权限范围)
SELECT u.* FROM sys_user u
WHERE u.del_flag = 0
AND (u.create_dept IN (SELECT dept_id FROM sys_dept WHERE FIND_IN_SET(dept_id, #{dataScope})))数据权限范围取决于用户角色的 data_scope 配置:
| data_scope 值 | 含义 | SQL 效果 |
|---|---|---|
| 1 | 全部数据 | 不追加条件 |
| 2 | 自定义数据 | dept_id IN (配置的部门) |
| 3 | 本部门数据 | dept_id = 当前部门 |
| 4 | 本部门及以下 | dept_id IN (本部门 + 下级) |
| 5 | 仅本人 | create_by = 当前用户 |
Mapper XML 写法
需要数据权限的查询必须写在 XML 中,因为拦截器按 mapperMethod 精确匹配:
xml
<!-- 正确:写在 XML 中,拦截器能匹配到 -->
<select id="selectUserPage" resultType="SysUserVO">
SELECT u.id, u.username, u.nickname, u.create_dept
FROM sys_user u
WHERE u.del_flag = 0
ORDER BY u.create_time DESC
</select>
<!-- 禁止:在 Service 层用 LambdaQueryWrapper,拦截器无法匹配 -->
lambdaQuery().eq(SysUserEntity::getStatus, "0").list();配置数据权限
- 在
sys_role表设置角色的data_scope值 data_scope = 2(自定义)时,在sys_role_dept配置可访问的部门- Mapper 方法名需要在
DataScopeInterceptor中注册
关键约束
- SQL 必须写在 Mapper XML 中,
DataScopeInterceptor按mapperMethod匹配改写 - 查询 SQL 必须包含
create_dept字段,拦截器基于此字段过滤 - 仅单表
selectById、insert、updateById、deleteById等内置方法允许用 MyBatis-Plus API - 数据权限与租户隔离可以叠加,两者互不影响
