当前位置: 首页 > article >正文

若依数据隔离 ${params.dataScope} 替换 优化为sql 替换

若依数据隔离 ${params.dataScope} 替换 优化为sql 替换

安全问题:有风险的SQL查询:MyBatis解决

若依框架的数据隔离是通过 ${params.dataScope} 实现的 
但是在代码安全扫描的时候$ 符会提示有风险的SQL查询:MyBatis
所以我们这里需要进行优化

参考:
MyBatis-Plus实现动态表名
MyBatis-Plus实现动态表名只能实现表名替换 也就是除了from 后面的$符号都替换不了
所以我们需要进行改造
在这里插入图片描述

导入依赖

 <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>

RequestDataHelper



import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;

import java.util.Map;

public class RequestDataHelper {
    /**
     * 请求参数存取
     */
    private static final ThreadLocal<Map<String, Object>> REQUEST_DATA = new ThreadLocal<>();

    /**
     * 设置请求参数
     *
     * @param requestData 请求参数 MAP 对象
     */
    public static void setRequestData(Map<String, Object> requestData) {
        REQUEST_DATA.set(requestData);
    }

    /**
     * 获取请求参数
     *
     * @param param 请求参数
     * @return 请求参数 MAP 对象
     */
    public static <T> T getRequestData(String param) {
        Map<String, Object> dataMap = getRequestData();
        if (CollectionUtils.isNotEmpty(dataMap)) {
            return (T) dataMap.get(param);
        }
        return null;
    }

    /**
     * 获取请求参数
     *
     * @return 请求参数 MAP 对象
     */
    public static Map<String, Object> getRequestData() {
        return REQUEST_DATA.get();
    }
}

MybatisPlusConfig





import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

@Configuration
public class MybatisPlusConfig {
    static List<String> tableList(){
        List<String> tables = new ArrayList<>();
        //表名 C55EA8171877E962E08DFF63AA367884123 可以为任意字符  建议复杂度高点 如果重复 会造成替换bug
        tables.add("C55EA8171877E962E08DFF63AA367884123");
        return tables;
    }

    @Autowired
    private List<SqlSessionFactory> sqlSessionFactoryList;

    @PostConstruct
    public void addMyInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // mybatis-plus DynamicTableNameInnerInterceptor 只能实现表名替换 所以这里我们优化了使用我们自己的拦截器LizzMybatisIntercepts
//        DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
//        dynamicTableNameInnerInterceptor.setTableNameHandler((sql, tableName) -> {
//            String newTable = null;
//            for (String table : tableList()) {
//                newTable = RequestDataHelper.getRequestData(table);
//                if (table.equals(tableName) && newTable!=null){
//                    tableName = newTable;
//                    break;
//                }
//            }
//            return tableName;
//        });
 // mybatis-plus DynamicTableNameInnerInterceptor 只能实现表名替换 所以这里我们优化了使用我们自己的拦截器LizzMybatisIntercepts
        LizzMybatisIntercepts lizzMybatisIntercepts = new LizzMybatisIntercepts();
        interceptor.addInnerInterceptor(lizzMybatisIntercepts);
        for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {
            sqlSessionFactory.getConfiguration().addInterceptor(interceptor);
        }
    }
}


LizzMybatisIntercepts


import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.sql.SQLException;

@Slf4j
public class LizzMybatisIntercepts implements InnerInterceptor {

    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        log.info("#####beforeQuery");
        String sql = boundSql.getSql();
        // 这里是获取到需要替换到的sql 通过 PluginUtils.mpBoundSql(boundSql); 替换   mybatis-plus表名替换源码的原理也是这个
        String params = RequestDataHelper.getRequestData("C55EA8171877E962E08DFF63AA367884123");
        String param = sql.replaceAll("C55EA8171877E962E08DFF63AA367884123", params);
        PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
        mpBs.sql(param);

    }


}

测试

mapper

    <select id="getList" resultType="com.wys.entity.User">
        SELECT *
	        FROM user where name=#{name} and C55EA8171877E962E08DFF63AA367884123

    </select>

UserController

    @GetMapping("/listUser")
    public List listUser(){

        RequestDataHelper.setRequestData(new HashMap<String, Object>() {{
            put("C55EA8171877E962E08DFF63AA367884123", "1=1");
        }});
       User user=new User();
        user.setName("111111");
        List list = userMapper.getList(user);
    
       return list;

    }

若依代码替换如下

相当于我们手动从实体类拿出来需要替换的sql 然后塞到我们的拦截器里面 有拦截器去替换

 // 若依数据隔离 ${params.dataScope} 替换 优化sql 替换
        String dataScope="";
        Map<String, Object> params = role.getParams();
        if (params!=null && params.size()>0){
          dataScope = params.get("dataScope").toString();

        }
        String finalDataScope = dataScope;
        RequestDataHelper.setRequestData(new HashMap<String, Object>() {{
            put("C55EA8171877E962E08DFF63AA367884123", finalDataScope);

        }});
		

修改前后对比图

在这里插入图片描述

执行sql打印
在这里插入图片描述
可以看到 我们的 sql可以正确替换


http://www.kler.cn/a/9842.html

相关文章:

  • [项目代码] YOLOv5 铁路工人安全帽安全背心识别 [目标检测]
  • git初始化和更新项目中的子模块
  • uniapp分享功能
  • 前端web
  • 原生 JavaScript基本内容和常用特性详解
  • 图书管理系统(Java实现)
  • 【SQL 必知必会】- 第十三课 创建高级联结
  • Python求矩阵的内积、外积、克罗内克直积、Khatri-Rao积
  • 医院不良事件上报系统源码,全套源代码
  • Spring框架中的Bean
  • QML控件--Container
  • 每日一问-ChapGPT-20230414-中医基础-四诊之问诊
  • vue3 history模式配置及nginx服务器配置
  • gRPC源码解读 传输层数据处理流程
  • 【spring】通过抽象类与ApplicationContext编写扩展性强的业务逻辑
  • 使用国密SSL证书,实现SSL/TLS传输层国密改造
  • 【你听说了吗】GPT-5据说已经学完了世界上现存所有的视频
  • 电脑自动录屏软件哪个好用 电脑自动录屏怎么设置
  • 剑指 Offer 49. 丑数
  • 【计算机组成原理 - 第二章】系统总线(完结)
  • css 导航栏效果
  • ICPC SWERC 2020 K - Unique Activities(SAM记录子串第一次结束位置 or SAM + hash)
  • ​分析新特征背后的内在逻辑,才能把握未来一段时期的科技发展新方向
  • Python 进阶指南(编程轻松进阶):十二、使用 Git 组织您的代码项目
  • springboot项目配置文件不允许出现明文密码的解决方法(jasypt使用方法)
  • ChatGPT 指令大全