数据权限的设计思路

Lewis
2022-11-25 / 0 评论 / 2 阅读 / 正在检测是否收录...

lavwi7wc.png

数据权限,主要进行数据的过滤,没相应的数据权限,则不能查询、操作相应的数
据。

数据权限实现方式如下:

  1. 用户登录后,获取部门 ID 数据权限列表
  2. 根据部门 ID 列表进行数据过滤,数据过滤表,都需要有部门 ID 字段

一、自定义权限过滤注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataFilter {
    /**
     * 表的别名
     */
    String tableAlias() default "";
    /**
     * 用户ID
     */
    String userId() default "creator";
    /**
     * 部门ID
     */
    String deptId() default "dept_id";
}

二、数据过滤,切面处理类

@Aspect
@Component
public class DataFilterAspect {

    @Before("dataFilterCut(datafilter)")
    public void dataFilter(JoinPoint point,DataFilter datafilter) {
        Object params = point.getArgs()[0];
        if(params != null && params instanceof Map){
            UserDetail user = SecurityUser.getUser();

            //如果是超级管理员或超级租户,则不进行数据过滤
            if(user.getSuperAdmin() == SuperAdminEnum.YES.value() ||
                    user.getSuperTenant() == SuperTenantEnum.YES.value()) {
                return ;
            }

            try {
                //否则进行数据过滤
                Map map = (Map)params;
                String sqlFilter = getSqlFilter(user, point);
                map.put(Constant.SQL_FILTER, new DataScope(sqlFilter));
            }catch (Exception e){

            }

            return ;
        }

        throw new RenException(ErrorCode.DATA_SCOPE_PARAMS_ERROR);
    }

    /**
     * 获取数据过滤的SQL
     */
    private String getSqlFilter(UserDetail user, JoinPoint point) throws Exception {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = point.getTarget().getClass().getDeclaredMethod(signature.getName(), signature.getParameterTypes());
        DataFilter dataFilter = method.getAnnotation(DataFilter.class);

        //获取表的别名
        String tableAlias = dataFilter.tableAlias();
        if(StringUtils.isNotBlank(tableAlias)){
            tableAlias +=  ".";
        }

        StringBuilder sqlFilter = new StringBuilder();
        sqlFilter.append(" (");

        //部门ID列表
        List<Long> deptIdList = user.getDeptIdList();
        if(CollUtil.isNotEmpty(deptIdList)){
            sqlFilter.append(tableAlias).append(dataFilter.deptId());

            sqlFilter.append(" in(").append(StringUtils.join(deptIdList, ",")).append(")");
        }

        //查询本人数据
        if(CollUtil.isNotEmpty(deptIdList)){
            sqlFilter.append(" or ");
        }
        sqlFilter.append(tableAlias).append(dataFilter.userId()).append("=").append(user.getId());

        sqlFilter.append(")");

        return sqlFilter.toString();
    }
}

三、数据过滤

public class DataFilterInterceptor implements InnerInterceptor {

    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        DataScope scope = getDataScope(parameter);
        // 不进行数据过滤
        if(scope == null || StrUtil.isBlank(scope.getSqlFilter())){
            return;
        }

        // 拼接新SQL
        String buildSql = getSelect(boundSql.getSql(), scope);

        // 重写SQL
        PluginUtils.mpBoundSql(boundSql).sql(buildSql);
    }

    private DataScope getDataScope(Object parameter){
        if (parameter == null){
            return null;
        }

        // 判断参数里是否有DataScope对象
        if (parameter instanceof Map) {
            Map<?, ?> parameterMap = (Map<?, ?>) parameter;
            for (Map.Entry entry : parameterMap.entrySet()) {
                if (entry.getValue() != null && entry.getValue() instanceof DataScope) {
                    return (DataScope) entry.getValue();
                }
            }
        } else if (parameter instanceof DataScope) {
            return (DataScope) parameter;
        }

        return null;
    }

    private String getSelect(String buildSql, DataScope scope){
        try {
            Select select = (Select) CCJSqlParserUtil.parse(buildSql);
            PlainSelect plainSelect = (PlainSelect) select.getSelectBody();

            Expression expression = plainSelect.getWhere();
            if(expression == null){
                plainSelect.setWhere(new StringValue(scope.getSqlFilter()));
            }else{
                AndExpression andExpression =  new AndExpression(expression, new StringValue(scope.getSqlFilter()));
                plainSelect.setWhere(andExpression);
            }

            return select.toString().replaceAll("'", "");
        }catch (JSQLParserException e){
            return buildSql;
        }
    }
}

四、配置类

@Configuration
public class DataScopeConfig {
    @Bean
    public InnerInterceptor dataFilterInterceptor() {
        return new DataFilterInterceptor();
    }
}
1

评论 (0)

取消