系统数据权限使用

数据权限是什么?

数据权限用于控制用户能看到的数据范围:全部、本部门、本部门含子部门、自定义部门、仅本人。

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 后无需手动处理数据权限,系统自动根据当前用户角色过滤数据,极大减少代码量。

  1. Mapper 继承 PigxBaseMapper<T>
  2. 业务层传入 DataScope.of(),即可按当前登录人角色自动套用数据权限
  3. 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 / 联表)

自定义XML配置
联表查询限制

MyBatis-Plus-Join 链式写法无法自动注入数据权限,联表查询请在 XML 里写标准 SQL。

  1. Mapper 方法增加 DataScope 参数
  2. 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 枚举只定义了 ALLCOUNT 两种函数类型,其他聚合函数无法自动处理。

不支持场景的解决方案

手动处理方案

对于不支持的聚合查询,需要通过 dataScopeHandle 计算权限范围,然后在 XML 中手动拼接 SQL。

  1. Service 调用 dataScopeHandle.calcScope() 计算权限范围
  2. 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>

工作原理速览

数据权限工作流程
  1. MyBatis-Plus 拦截器(DataScopeInnerInterceptor)拦截带 DataScope 参数的查询
  2. 根据当前用户角色计算可见的部门/用户名
  3. 在原 SQL 外包一层子查询,自动追加 dept_idcreate_by 过滤

示例 SQL 包装:

SELECT * FROM (<原始SQL>) temp_data_scope WHERE temp_data_scope.dept_id IN (可见部门)