Spring Boot + MyBatisPlus 实现数据权限的控制

Spring Boot中使用注解的方式实现数据权限控制

上一篇介绍了使用mybatis结合aop的方式实现数据权限控制,本次介绍使用mybatisPlus的拦截器功能实现数据权限控制,场景类似,不再赘述。

1、自定义注解

@Target( ElementType.METHOD )
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataScope {

    /**
     * 当前功能的authKey,根据authKey去查询当前用户的具体权限值
     */
    String authKey() default "";

    /**
     * 需要加数据权限范围的表别名,单位权限
     */
    String comTableName() default "sys_dept";

    String comFieldName() default "dept_id";

}

2、自定义拦截器

public class DataScopeInterceptor implements InnerInterceptor {
    /**
     * {@link Executor#(MappedStatement, Object, RowBounds, ResultHandler, BoundSql)} 操作前置处理
     * <p>
     * 改改sql啥的
     *
     * @param executor      Executor(可能是代理对象)
     * @param ms            MappedStatement
     * @param parameter     parameter
     * @param rowBounds     rowBounds
     * @param resultHandler resultHandler
     * @param boundSql      boundSql
     */
    @SneakyThrows
    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        // 获取当前用户id
        Long userId = SecurityUtils.getUserId();
        //获取当前用户所在部门id
        Long deptId = SecurityUtils.getDeptId();
        // 获取方法上的注解
        DataScope dataScope = this.getDataScope(ms);
        if (dataScope != null) {
            // 获取注解中的authKey
            String authKey = dataScope.authKey();
            // 根据authKey和角色id查询当前用户在该功能下的权限值
            //roleService.getDataValueByAuthKeyAndRoleId(authKey, role.getId());
            //默认查询当前部门的数据,可按照自己需求调整
            Integer dataValue =1;
            if (dataValue != null) {
                // 获取原始sql语句
                String originalSql = boundSql.getSql();
                // 根据不同的权限值,拼接不同的where条件
                String whereSql = this.getWhereSqlByDataValue(dataValue, dataScope, userId,deptId);
                if (StringUtils.isNotBlank(whereSql)) {
                    // 将拼接后的sql重新设置到boundSql中
                    String newSql = originalSql + whereSql;
                    Field sqlField = boundSql.getClass().getDeclaredField("sql");
                    sqlField.setAccessible(true);
                    sqlField.set(boundSql, newSql);
                }
            }
        }
        InnerInterceptor.super.beforeQuery(executor, ms, parameter, rowBounds, resultHandler, boundSql);
    }


    /**
     * 根据不同的权限值,拼接不同的where条件
     * @param dataValue 权限值
     * @param dataScope 注解信息
     * @param userId 用户id
     * @return where条件语句
     */
    private String getWhereSqlByDataValue(Integer dataValue, DataScope dataScope, Long userId,Long deptId) {
        StringBuilder whereSql = new StringBuilder();
        switch (dataValue) {
            case 1: // 本单位权限
                whereSql.append(" and ").append(dataScope.comTableName()).append(".").append(dataScope.comFieldName()).append(" = ").append(deptId);
                break;
            case 2: // 本单位及下级单位权限
                // 获取当前用户所在部门及下级部门id列表
                String deptSql="SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors )";
                whereSql.append(" and ").append(dataScope.comTableName()).append(".").append(dataScope.comFieldName()).append(" in ").append("(").append(StrUtil.format(deptSql,deptId,deptId)).append(")");
                break;
            case 3: // 无权限
                whereSql.append(" and 1 = 0"); // 拼接一个恒假条件,使得查询结果为空
                break;
            case 4: // 所有数据权限
                break;
            default:
                break;
        }
        return whereSql.toString();
    }

    /**
     * 获取方法上的注解信息
     * @param mappedStatement 拦截器参数
     * @return 注解对象或null
     */
    private DataScope getDataScope(MappedStatement mappedStatement) {
        String id = mappedStatement.getId();
        String className = id.substring(0, id.lastIndexOf("."));
        String methodName = id.substring(id.lastIndexOf(".") + 1);
        Class<?> clazz = null;
        try {
            clazz = Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        Method[] methods = clazz != null ? clazz.getDeclaredMethods() : null;
        if (methods != null) {
            for (Method method : methods) {
                if (method.getName().equals(methodName)) {
                    return method.getAnnotation(DataScope.class);
                }
            }
        }
        return null;
    }
}

3、注册拦截器

@Configuration
public class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor=new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new DataScopeInterceptor());
        return interceptor;
    }
}

4、注解使用

该注解只能作用于mapper层的方法上,使用在其他地方无法生效

//默认查询部门下的用户列表
@DataScope
List<SysUserDto> queryAllUserList(@Param("po") SysUserDto sysUserDto);

对应的sql如下:

<select id="queryAllUserList" resultMap="SysUserMap">
        select * from sys_user LEFT JOIN sys_dept ON sys_user.dept_id=sys_dept.dept_id where 1=1
    </select>

以上就是通过mybatisPlus拦截器实现数据权限控制的基本使用方式。

请登录后发表评论

    没有回复内容