系统数据权限使用
数据权限是什么?
数据权限用于控制用户能看到的数据范围:全部、本部门、本部门含子部门、自定义部门、仅本人。
PIGX 通过数据权限机制,让"谁能看什么"落在 SQL 过滤上,而不是业务代码手写,极大简化了开发复杂度。
开始之前
⚠必备字段
数据表需要具备以下字段:
dept_id:标记数据所属部门
create_by:标记数据创建人
CREATE TABLE `business_data` (
-- 业务数据表正常字段
`dept_id` BIGINT NOT NULL COMMENT '所属部门ID(数据权限必备字段)',
`create_by` VARCHAR(64) NOT NULL COMMENT '创建人(数据权限必备字段)',
)
常用用法
方式一:PigxBaseMapper 扩展(推荐)
✓推荐方式
继承 PigxBaseMapper 后无需手动处理数据权限,系统自动根据当前用户角色过滤数据,极大减少代码量。
- Mapper 继承
PigxBaseMapper<T>
- 业务层传入
DataScope.of(),即可按当前登录人角色自动套用数据权限
queryWrapper 可选,用于叠加业务条件
// Mapper
public interface DemoMapper extends PigxBaseMapper<DemoEntity> {
}
// Service 示例
DataScope scope = DataScope.of();
List<DemoEntity> list = demoMapper.selectListByScope(Wrappers.emptyWrapper(), scope);
IPage<DemoEntity> page = demoMapper.selectPageByScope(new Page<>(1, 10), Wrappers.emptyWrapper(), scope);
long count = demoMapper.selectCountByScope(Wrappers.emptyWrapper(), scope.func(DataScopeFuncEnum.COUNT));
方式二:自定义 XML(适合复杂 SQL / 联表)
⚠联表查询限制
MyBatis-Plus-Join 链式写法无法自动注入数据权限,联表查询请在 XML 里写标准 SQL。
- Mapper 方法增加
DataScope 参数
- Service 调用时传
DataScope.of(),SQL 正常写,无需手动拼权限条件
// Mapper,具体可以参考 PIGX 这个例子代码
IPage<UserVO> getUserVosPage(Page page, @Param("query") UserDTO userDTO, DataScope dataScope);
常见场景
数据权限提供了灵活的配置方式,以适应不同的业务场景。
需要放开权限查询所有数据时,设置 dataScope.setSkip(true)。
DataScope scope = DataScope.of();
scope.setSkip(true); // 跳过数据权限
demoMapper.selectListByScope(Wrappers.emptyWrapper(), scope);
特别限制
支持范围
数据权限仅支持以下查询类型:
| 查询类型 | 支持状态 | 说明 |
|---|
| 列表查询 | ✅ 支持 | SELECT * FROM ... |
| COUNT 统计 | ✅ 支持 | SELECT COUNT(1) FROM ... |
| SUM 求和 | ❌ 不支持 | 需手动拼接过滤条件 |
| AVG 平均值 | ❌ 不支持 | 需手动拼接过滤条件 |
| MAX/MIN | ❌ 不支持 | 需手动拼接过滤条件 |
| 其他复杂聚合 | ❌ 不支持 | 需手动拼接过滤条件 |
原因说明
数据权限通过 MyBatis 拦截器(DataScopeInnerInterceptor)实现,在原始 SQL 外包装子查询后追加过滤条件。DataScopeFuncEnum 枚举只定义了 ALL 和 COUNT 两种函数类型,其他聚合函数无法自动处理。
不支持场景的解决方案
💡手动处理方案
对于不支持的聚合查询,需要通过 dataScopeHandle 计算权限范围,然后在 XML 中手动拼接 SQL。
- Service 调用
dataScopeHandle.calcScope() 计算权限范围
- XML 使用
<if> 标签动态拼接过滤条件,手动拼接 SQL
// Service 层
@RequiredArgsConstructor
public class DemoServiceImpl implements DemoService {
private final RemoteDataScopeService dataScopeService;
private final DemoMapper demoMapper;
public BigDecimal getTotalAmount() {
// 构建空的数据权限对象
DataScope scope = DataScope.of();
// pigx 自动计算权限范围
new PigxDefaultDataScopeHandle(dataScopeService).calcScope(scope);
// 传递具体的部门列表和用户名,而不是 DataScope 对象
return demoMapper.selectTotalAmount(scope.getDeptList(), scope.getUsername());
}
}
// Mapper 接口
public interface DemoMapper extends BaseMapper<DemoEntity> {
BigDecimal selectTotalAmount(@Param("deptList") List<Long> deptList,
@Param("username") String username);
}
<!-- Mapper XML -->
<select id="selectTotalAmount" resultType="java.math.BigDecimal">
SELECT SUM(amount)
FROM business_data
WHERE del_flag = '0'
<!-- 个人数据权限 -->
<if test="username != null and username != ''">
AND create_by = #{username}
</if>
<!-- 部门数据权限 -->
<if test="deptList != null and deptList.size() > 0">
AND dept_id IN
<foreach collection="deptList" item="deptId" open="(" separator="," close=")">
#{deptId}
</foreach>
</if>
</select>
工作原理速览
- MyBatis-Plus 拦截器(
DataScopeInnerInterceptor)拦截带 DataScope 参数的查询
- 根据当前用户角色计算可见的部门/用户名
- 在原 SQL 外包一层子查询,自动追加
dept_id 或 create_by 过滤
示例 SQL 包装:
SELECT * FROM (<原始SQL>) temp_data_scope WHERE temp_data_scope.dept_id IN (可见部门)