Skip to content

数据权限

作者:唐亚峰 | battcn
字数统计:492 字

多维度数据权限

为保障不同决策身份的用户数据安全,会将划分每个用户可见的数据范围

  • 全部:可以看所有的数据(常为管理员角色)
  • 本级及子级:常用语组织架构领导层
  • 本级:用处较少,常用部门组长之类的
  • 自定义:可以根据自己业务场景自定义权限范围和资源
  • 个人:顾名思义,只能看自己创建的数据

wemirr-platform 只需进行少量的规则代码配置,即可实现灵活多维度的数据权限控制。

使用方式

手动使用

手动API调用,通过 DataPermissionUtils.execute() 方式构建 DataPermissionRule 即可

java
@GetMapping
@Parameters({
        @Parameter(name = "name", description = "名称", in = ParameterIn.QUERY),
        @Parameter(name = "principal", description = "账号", in = ParameterIn.QUERY)
})
@Operation(summary = "查询日志 - [DONE] - [Levin]", description = "查询日志 - [DONE] - [Levin]")
@PreAuthorize("hasAuthority('log:login:page')")
public Page<LoginLog> query(PageRequest request, String name, String principal) {
    return DataPermissionUtils.executeDefaultDataPermissionRule(() ->
            loginLogService.page(request.buildPage(), Wraps.<LoginLog>lbQ().like(LoginLog::getName, name)
                    .like(LoginLog::getPrincipal, principal).orderByDesc(LoginLog::getCreatedTime)));
}

注解使用

可以指定多个字段多个维度的数据权限,可以自行灵活定义

java
@DataScope(columns = {
        @DataColumn(name = Entity.CREATE_USER_COLUMN,resource = DataResourceType.USER),
        @DataColumn(name = "company_id",resource = DataResourceType.COMPANY),
})
IPage<UserResp> findPage(@Param("page") IPage<User> page, @Param("req") UserPageReq req);

核心实现

基于 MP 提供的 MultiDataPermissionHandler 实现了动态多维度数据权限

java
@Slf4j
@RequiredArgsConstructor
public class DataScopePermissionHandler implements MultiDataPermissionHandler {

    private final AuthenticationContext context;


    @SneakyThrows
    @Override
    public Expression getSqlSegment(final Table table, Expression where, String mappedStatementId) {
        // 匿名用户不进入数据权限插件
        if (context.anonymous()) {
            return null;
        }
        if (log.isDebugEnabled()) {
            log.debug("sql statementId{},where - {}", mappedStatementId, where);
        }
        // 默认从当前线程上下文获取,兼容  DataPermissionUtils.executeWithDataPermissionRule 方式
        DataPermissionRule rule = DataPermissionRuleHolder.peek();
        if (rule == null) {
            // 注解的优先级最低
            rule = DataPermissionUtils.getDataPermissionRuleByMappedStatementId(mappedStatementId);
        }
        return buildAnnotationExpression(table, rule);
    }

    private Expression buildAnnotationExpression(Table table, DataPermissionRule rule) {
        if (rule == null) {
            return null;
        }
        final DataPermission permission = context.dataPermission();
        if (permission.getScopeType() == DataScopeType.ALL || rule.isIgnore()) {
            return null;
        }
        final List<DataPermissionRule.Column> columns = rule.getColumns();
        final List<Expression> conditions = DataPermissionUtils.buildConditions(context, table, columns);
        if (CollUtil.isEmpty(conditions)) {
            return null;
        }
        // 使用循环将条件逐个与前面的条件组合起来
        return conditions.stream().reduce(AndExpression::new).orElse(null);
    }
}