# 数据(范围)权限控制

某些场景下的数据查询需要绑定一些强制条件,用于数据权限查看范围控制,如只能查看本部门的 销售订单数据。 不同于多租户的全局数据隔离,这种场景需要的是在这些特定业务功能里过滤查询条件,仅显示其权限范围内的数据,diboot 数据权限就是针对这种场景的解决方案。

# 使用步骤

示例场景:如销售订单业务对象有个部门id字段,需要控制用户只能访问本部门的销售订单数据。

实现步骤为: 加注解+写实现

# 1. 加注解:在需要控制数据范围的对象Entity中的过滤字段上添加@DataAccessCheckpoint注解。

示例代码:

// 销售订单对象,基于部门来过滤数据查看范围
public class SalesOrder extends BaseEntity{
    // ...
    // 数据权限检查点,按部门来过滤
    @DataAccessCheckpoint
    private Long orgId;
    //...
}
1
2
3
4
5
6
7
8

# 2. 写实现:实现DataAccessInterface接口,返回当前用户可访问的合法ID集合

@Component
public class MyDataAccessPermissionImpl implements DataAccessInterface {
//如依赖了IAM组件,可选继承DataAccessPermissionUserOrgImpl实现
//public class MyDataAccessPermissionImpl extends DataAccessPermissionUserOrgImpl {

    @Autowired
    private IamOrgService iamOrgService;

    @Override
    public List<Serializable> getAccessibleIds(Class<?> entityClass, String fieldName) {
        // 获取当前登录用户
        IamUser currentUser = IamSecurityUtils.getCurrentUser();
        // 提取其可访问ids
        List<Serializable> accessibleIds = new ArrayList<>();
        //按部门过滤
        if(Cons.FieldName.orgId.name().equals(fieldName)){ 
            //示例:可访问数据范围为: orgId 为 当前部门ID 或 子部门 IDs
            Long currentOrgId = currentUser.getOrgId();
            accessibleIds.add(currentOrgId);
            List<Long> childOrgIds = iamOrgService.getChildOrgIds(currentOrgId);
            if(V.notEmpty(childOrgIds)){
                accessibleIds.addAll(childOrgIds);
            }
        }
        // 按用户过滤
        else if(Cons.FieldName.userId.name().equals(fieldName)){
            //示例:可访问数据范围为: 本人
            accessibleIds.add(currentUser.getId());
        }
        // 按其他字段过滤...
        
        // 返回合法ID集合
        return accessibleIds;
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# 3. Spring config类中配置Mybatis-plus数据权限拦截器,启用数据(范围)权限拦截

@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    // 启用diboot数据权限拦截器,将拦截并修改需要控制数据权限的SQL
    interceptor.addInnerInterceptor(new DataPermissionInterceptor(new DataAccessControlHandler())); // (v2.9及之后版本的添加方式)
    // interceptor.addInnerInterceptor(new DataAccessControlInterceptor()); // (v2.8及之前版本的添加方式)
    interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
    return interceptor;
}
1
2
3
4
5
6
7
8
9

这样就可以针对SalesOrder数据查询的SQL中,强制添加 org_id IN(100001, 100002) 的过滤条件,实现数据访问范围控制。

# 4. 忽略某特定SQL的数据权限拦截 (since v2.9.0)

数据(范围)权限一旦启用,默认将会拦截所有针对该Entity的SQL查询,但某些情况下需要忽略某个特定SQL的拦截,该场景可以添加拦截忽略注解实现。

  • 使用拦截忽略注解 @InterceptorIgnore 忽略某个查询
@Mapper
public interface XxxMapper extends BaseCrudMapper<Xxx> {
    
    @InterceptorIgnore // 添加该注解后,数据权限拦截器将忽略该查询
    long countAll();
    
}
1
2
3
4
5
6
7

# 基于岗位的范围控制

如果您的业务场景中数据权限范围跟岗位关联,不同岗位的用户可以访问不同范围的数据,可以结合diboot-*-admin前端岗位管理功能中预置的数据权限设置,实现前端配置后端控制。 diboot IAM组件也提供了后端的默认实现类 DataAccessPermissionUserOrgImpl 可供使用或扩展。 岗位中的数据权限配置示例