0.注意事项

        a.代码可能不全,大致读一下逻辑即可实现

        b.重点就是拦截器sql拼接部分,其他可按不同场景个性化
        c.如果拦截器不起作用可参考6服务启动时操作或参考下方配置拦截器

@Configuration
@MapperScan("com.rtzh.ejjzhgd.web.**.mapper")
@EnableConfigurationProperties(value = DataScopeProperties.class)
public class MybatisPlusConfig {
 
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        interceptor.addInnerInterceptor(new QueryParameterInnerInterceptor());
        return interceptor;
    }

    @Bean
    @ConfigurationProperties(prefix = "pagehelper")
    public Properties pageHelperProperties() {
        return new Properties();
    }
}

        


1.使用方法


        查询前执行该方法即可 参数1:字段名,参数2:自定义id可传null,在拦截器更具用户查询
        该方法就是为了往ThreadLocal set数据
        DataScopeHelper.start("office_id", filterIds); 

  示例:

@Override
public Object test() {

    LambdaQueryWrapper<RtPro> lambdaQuery = new LambdaQueryWrapper();
    lambdaQuery.ne(RtPro::getProId,"1");
    lambdaQuery.last("limit 10");
    DataScopeHelper.start("dept_id", new HashSet<>(Arrays.asList("id")));
    return  rtProMapper.selectList(lambdaQuery);
}
2.线程缓存


public class DataScopeHelper {
    private static final ThreadLocal<DataScope> DATA_PERMISSION = new ThreadLocal();

    public DataScopeHelper() {
    }

    public static void start(DataScope dataScope) {
        DATA_PERMISSION.set(dataScope);
    }

    public static void start(String scopeName, Set<String> deptIds) {
        DataScope dataScope = new DataScope();
        dataScope.setScopeName(scopeName);
        dataScope.setDeptIds(deptIds);
        DATA_PERMISSION.set(dataScope);
    }

    public static void startDataScope(String scopeName, String... deptIds) {
        Object idSet;
        if (deptIds != null && deptIds.length > 0) {
            idSet = (Set)Arrays.stream(deptIds).filter(StringUtils::isNotEmpty).collect(Collectors.toSet());
        } else {
            idSet = new HashSet();
        }
        start(scopeName, (Set)idSet);
    }

    public static DataScope getLocalDataPermissions() {
        return (DataScope)DATA_PERMISSION.get();
    }

    public static void clearDataPermissions() {
        DATA_PERMISSION.remove();
    }
}

3.mybatis拦截器


@Intercepts({@Signature(
    type = Executor.class,
    method = "query",
    args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
), @Signature(
    type = Executor.class,
    method = "query",
    args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}
)})
public class DataScopeInterceptor implements Interceptor {
    private static final Logger log = LoggerFactory.getLogger(DataScopeInterceptor.class);
    private DataScopeHandler dataScopeHandler;
    private DataScopeProperties dataScopeProperties;

    public Object intercept(Invocation invocation) throws Throwable {
        if (!this.dataScopeProperties.getEnabled()) {
            return invocation.proceed();
        } else {
            Object[] args = invocation.getArgs();
            MappedStatement ms = (MappedStatement)args[0];
            Object parameter = args[1];
            RowBounds rowBounds = (RowBounds)args[2];
            ResultHandler resultHandler = (ResultHandler)args[3];
            Executor executor = (Executor)invocation.getTarget();
            CacheKey cacheKey;
            BoundSql boundSql;
            if (args.length == 4) {
                boundSql = ms.getBoundSql(parameter);
                cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql);
            } else {
                cacheKey = (CacheKey)args[4];
                boundSql = (BoundSql)args[5];
            }

            String originalSql = boundSql.getSql();
            Object parameterObject = boundSql.getParameterObject();
            DataScope dataScope = this.findDataScopeObject(parameterObject);
            if (dataScope == null) {
                dataScope = DataScopeHelper.getLocalDataPermissions();
                DataScopeHelper.clearDataPermissions();
            }

            if (dataScope == null) {
                return invocation.proceed();
            } else {
                UserVO userVO = UserInfoUtils.getCurrentUser();
                if (this.isAdminRole(userVO.getRoleList(), this.dataScopeProperties.getAdminRoleId())) {
                    return invocation.proceed();
                } else {
                    String scopeName = StringUtils.isBlank(dataScope.getScopeName()) ? this.dataScopeProperties.getScopeKey() : dataScope.getScopeName();
                    Set<String> deptIds = dataScope.getDeptIds();
                    if (CollectionUtil.isEmpty(deptIds)) {
                        deptIds = this.dataScopeHandler.findDeptIds(userVO);
                    }

if (CollectionUtil.isNotEmpty(deptIds)) {
    String upperCaseSql = originalSql.toUpperCase();
    boolean isLimitEnd = StringUtils.endsWithRegex(upperCaseSql, "LIMIT\\s*\\d+\\s*,\\s*\\d+\\s*$|LIMIT\\s*\\d+\\s*");
    String join = "'" + CollectionUtil.join(deptIds, "','") + "'";
    if(isLimitEnd){
        int limit = upperCaseSql.lastIndexOf("LIMIT");
        String limitSql = upperCaseSql.substring(limit, upperCaseSql.length());
        String selectSql = upperCaseSql.substring(0, limit);
        originalSql = "select * from (" + selectSql + ") temp_data_scope where temp_data_scope." + scopeName + " in (" + join + ") " + limitSql;
    }else {
        originalSql = "select * from (" + originalSql + ") temp_data_scope where temp_data_scope." + scopeName + " in (" + join + ")";
    }
    boundSql = new BoundSql(ms.getConfiguration(), originalSql, boundSql.getParameterMappings(), parameter);
}
                    return executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql);
                }
            }
        }
    }

    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    public void setProperties(Properties properties) {
    }

    private DataScope findDataScopeObject(Object parameterObj) {
        if (parameterObj instanceof DataScope) {
            return (DataScope)parameterObj;
        } else {
            if (parameterObj instanceof Map) {
                Iterator var2 = ((Map)parameterObj).values().iterator();

                while(var2.hasNext()) {
                    Object val = var2.next();
                    if (val instanceof DataScope) {
                        return (DataScope)val;
                    }
                }
            }

            return null;
        }
    }

    private Boolean isAdminRole(List<SysRole> roleList, String adminRoleId) {
        if (roleList == null) {
            return Boolean.FALSE;
        } else {
            Iterator var3 = roleList.iterator();

            SysRole sysRole;
            do {
                if (!var3.hasNext()) {
                    return Boolean.FALSE;
                }

                sysRole = (SysRole)var3.next();
            } while(!adminRoleId.equals(sysRole.getRoleId()));

            return Boolean.TRUE;
        }
    }

    public DataScopeInterceptor(final DataScopeHandler dataScopeHandler, final DataScopeProperties dataScopeProperties) {
        this.dataScopeHandler = dataScopeHandler;
        this.dataScopeProperties = dataScopeProperties;
    }
}

4.缓存处理类

public class DataScopeHelper {
    private static final ThreadLocal<DataScope> DATA_PERMISSION = new ThreadLocal();

    public DataScopeHelper() {
    }

    public static void start(DataScope dataScope) {
        DATA_PERMISSION.set(dataScope);
    }

    public static void start(String scopeName, Set<String> deptIds) {
        DataScope dataScope = new DataScope();
        dataScope.setScopeName(scopeName);
        dataScope.setDeptIds(deptIds);
        DATA_PERMISSION.set(dataScope);
    }

    public static void startDataScope(String scopeName, String... deptIds) {
        Object idSet;
        if (deptIds != null && deptIds.length > 0) {
            idSet = (Set)Arrays.stream(deptIds).filter(StringUtils::isNotEmpty).collect(Collectors.toSet());
        } else {
            idSet = new HashSet();
        }

        start(scopeName, (Set)idSet);
    }

    public static DataScope getLocalDataPermissions() {
        return (DataScope)DATA_PERMISSION.get();
    }

    public static void clearDataPermissions() {
        DATA_PERMISSION.remove();
    }
}

5.ThreadLocal缓存类型实体类

public class DataScope {
    //字段    
    private String scopeName;
    //数据id
    private Set<String> deptIds;
}

/**
* 正则校验以什么结尾
* @param input
* @param regex
* @return
*/
public static boolean endsWithRegex(String input, String regex) {
    // 将正则表达式编译成Pattern对象
    Pattern pattern = Pattern.compile(regex);
    // 使用matcher方法检查是否匹配字符串的结尾
    return pattern.matcher(input).find();
}

6.服务启动初始化数据-参考

a/**
 * @author mm
 * @Date 2024-03-24 14:33
 * @Desc
 */
@Slf4j
@Configuration
@EnableConfigurationProperties(value = DataScopeProperties.class)
public class DataScopeInterceptorConfig {

    @Autowired
    private DataScopeProperties dataScopeProperties;

    @Autowired
    private List<SqlSessionFactory> sqlSessionFactoryList;

    @Autowired
    private CloudRedisRepository redisRepository;

    @Resource(name="auSysOfficeServiceImpl")
    private com.rtzh.ejjzhgd.web.au.service.SysOfficeService sysOfficeService;

    //全部数据权限公司id
    private static final Set<String> allDataCompanyIds = Sets.newHashSet("000");//国网根节点 最大权限 TODO 参数配置到yml中

    public DataScopeInterceptorConfig() {
    }

/*    @Bean
    @ConfigurationProperties(
            prefix = "pagehelper"
    )
    public Properties pageHelperProperties() {
        return new Properties();
    }*/

    /**
     * 数据权限插件
     * 框架过滤规则: originalSql = "select * from (" + originalSql + ") temp_data_scope where temp_data_scope." + scopeName + " in (" + join + ")";
     * 业务sql执行前的配置
     * DataScopeHelper.start("office_id", null);  // 将会使用本【addDataFilterInterceptor的结果 (deptIds) 过滤数据】,前提 原查询字段里 有 office_id ;
     *
     * DataScopeHelper.start("office_id", filterIds);  // 将会使用 filterIds 过滤 原数据 ,前提 原查询字段里 有 office_id ;
     *
     * @return DataScopeInterceptor
     */
    @PostConstruct
    public void addDataFilterInterceptor() {
        log.error("addDataFilterInterceptor 数据权限过滤 WEB 配置启动 ");
        Iterator var3 = this.sqlSessionFactoryList.iterator();
        //数据权限插件
        DataScopeInterceptor dataScopeInterceptor = new DataScopeInterceptor(new DataScopeHandler(redisRepository) {
            @Override
            public Set<String> findDeptIds(UserVO userVO) {
                //TODO 以下默认过滤 根据业务实际情况编码
                Set<String> deptIds = new HashSet<>();
                //当前用户如果找不到对应的数据权限,则默认为所在机构及以下机构
                String varCompanyId = null;
                String varDeptId = null;
                if (StringUtils.isNotBlank(userVO.getCompanyId())) {
                    varCompanyId = this.getRedisRepository().getHashValues(SecurityConstants.DATA_SCOPE_KEY, userVO.getCompanyId());
                }
                if (StringUtils.isNotBlank(userVO.getDeptId())) {
                    varDeptId = this.getRedisRepository().getHashValues(SecurityConstants.DATA_SCOPE_KEY, userVO.getDeptId());
                }
                if (StringUtils.isBlank(varCompanyId) && StringUtils.isBlank(varDeptId)) {
                    getDefaultPerm(userVO.getCompanyId(), deptIds);
                } else {
                    if (StringUtils.isNotBlank(varCompanyId)) {
                        deptIds.addAll(JSONArray.parseArray(varCompanyId, String.class));
                    }
                    if (StringUtils.isNotBlank(varDeptId)) {
                        deptIds.addAll(JSONArray.parseArray(varDeptId, String.class));
                    }
                }
                log.warn("DataScopeInterceptorConfig : deptIds = {} ",deptIds);
                return deptIds;
            }
        }, dataScopeProperties);

        while (var3.hasNext()) {
            SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) var3.next();
            sqlSessionFactory.getConfiguration().addInterceptor(dataScopeInterceptor);
        }
    }


    /**
     * 根据当前用户获取默认数据权限
     * 目前只根据用户所在的公司来判断,不判断部门
     * TODO 具体根据产品规定默认权限来进行
     * @param companyId 公司id
     * @param dataPerms 数据权限
     */
    private void getDefaultPerm(String companyId, Set<String> dataPerms) {
        //有全数据权限
        if (allDataCompanyIds.contains(companyId)) {
            dataPerms.clear();
            return;
        }
        //查询下级机构
        dataPerms.addAll(sysOfficeService.getChildIds(companyId));
    }
}

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐