mirror of https://github.com/jeecgboot/jeecg-boot
---重构表字典逻辑,深度解决SQL注入漏洞问题,新旧版本都可以参考此修改合并---
(重点针对表名和字段进行单独check处理,更严格的格式要求,可能会导致一些特殊字典用法出问题,请根据自己业务做灵活调整) org\jeecg\common\exception\JeecgSqlInjectionException.java(+) org\jeecg\common\exception\JeecgBootExceptionHandler.java org\jeecg\common\util\security\AbstractQueryBlackListHandler.java org\jeecg\common\util\SqlInjectionUtil.java org\jeecg\modules\system\controller\DuplicateCheckController.java org\jeecg\modules\system\mapper\xml\SysDictMapper.xml org\jeecg\modules\system\mapper\SysDictMapper.java org\jeecg\modules\system\service\impl\SysDictServiceImpl.java org\jeecg\modules\system\service\ISysDictService.javapull/5377/head
parent
58aebdbba4
commit
44952c79c2
|
@ -1,6 +1,7 @@
|
|||
package org.jeecg.common.exception;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.shiro.authz.AuthorizationException;
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
|
@ -16,8 +17,6 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
|
|||
import org.springframework.web.multipart.MaxUploadSizeExceededException;
|
||||
import org.springframework.web.servlet.NoHandlerFoundException;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 异常处理器
|
||||
*
|
||||
|
@ -133,4 +132,24 @@ public class JeecgBootExceptionHandler {
|
|||
return Result.error("Redis 连接异常!");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* SQL注入风险,全局异常处理
|
||||
*
|
||||
* @param exception
|
||||
* @return
|
||||
*/
|
||||
@ExceptionHandler(JeecgSqlInjectionException.class)
|
||||
public Result<?> handleSQLException(Exception exception) {
|
||||
String msg = exception.getMessage().toLowerCase();
|
||||
final String extractvalue = "extractvalue";
|
||||
final String updatexml = "updatexml";
|
||||
boolean hasSensitiveInformation = msg.indexOf(extractvalue) >= 0 || msg.indexOf(updatexml) >= 0;
|
||||
if (msg != null && hasSensitiveInformation) {
|
||||
log.error("校验失败,存在SQL注入风险!{}", msg);
|
||||
return Result.error("校验失败,存在SQL注入风险!");
|
||||
}
|
||||
return Result.error("校验失败,存在SQL注入风险!" + msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package org.jeecg.common.exception;
|
||||
|
||||
/**
|
||||
* @Description: jeecg-boot自定义SQL注入异常
|
||||
* @author: jeecg-boot
|
||||
*/
|
||||
public class JeecgSqlInjectionException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public JeecgSqlInjectionException(String message){
|
||||
super(message);
|
||||
}
|
||||
|
||||
public JeecgSqlInjectionException(Throwable cause)
|
||||
{
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public JeecgSqlInjectionException(String message, Throwable cause)
|
||||
{
|
||||
super(message,cause);
|
||||
}
|
||||
}
|
|
@ -2,7 +2,10 @@ package org.jeecg.common.util;
|
|||
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jeecg.common.constant.SymbolConstant;
|
||||
import org.jeecg.common.exception.JeecgBootException;
|
||||
import org.jeecg.common.exception.JeecgSqlInjectionException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Set;
|
||||
|
@ -47,7 +50,7 @@ public class SqlInjectionUtil {
|
|||
* @param request:
|
||||
* @Return: void
|
||||
*/
|
||||
public static void checkDictTableSign(String dictCode, String sign, HttpServletRequest request) {
|
||||
private static void checkDictTableSign(String dictCode, String sign, HttpServletRequest request) {
|
||||
//表字典SQL注入漏洞,签名校验
|
||||
String accessToken = request.getHeader("X-Access-Token");
|
||||
String signStr = dictCode + SqlInjectionUtil.TABLE_DICT_SIGN_SALT + accessToken;
|
||||
|
@ -60,11 +63,72 @@ public class SqlInjectionUtil {
|
|||
}
|
||||
|
||||
/**
|
||||
* 返回查询表名
|
||||
* <p>
|
||||
* sql注入过滤处理,遇到注入关键字抛异常
|
||||
* @param value
|
||||
*
|
||||
* @param table
|
||||
*/
|
||||
public static void filterContent(String value) {
|
||||
filterContent(value, null);
|
||||
private static Pattern tableNamePattern = Pattern.compile("^[a-zA-Z][a-zA-Z0-9_]{0,63}$");
|
||||
public static String getSqlInjectTableName(String table) {
|
||||
table = table.trim();
|
||||
/**
|
||||
* 检验表名是否合法
|
||||
*
|
||||
* 表名只能由字母、数字和下划线组成。
|
||||
* 表名必须以字母开头。
|
||||
* 表名长度通常有限制,例如最多为 64 个字符。
|
||||
*/
|
||||
boolean isValidTableName = tableNamePattern.matcher(table).matches();
|
||||
if (!isValidTableName) {
|
||||
String errorMsg = "表名不合法,存在SQL注入风险!--->" + table;
|
||||
log.error(errorMsg);
|
||||
throw new JeecgSqlInjectionException(errorMsg);
|
||||
}
|
||||
|
||||
//进一步验证是否存在SQL注入风险
|
||||
filterContent(table);
|
||||
return table;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 返回查询字段
|
||||
* <p>
|
||||
* sql注入过滤处理,遇到注入关键字抛异常
|
||||
*
|
||||
* @param field
|
||||
*/
|
||||
static final Pattern fieldPattern = Pattern.compile("^[a-zA-Z0-9_]+$");
|
||||
public static String getSqlInjectField(String field) {
|
||||
field = field.trim();
|
||||
|
||||
if (field.contains(SymbolConstant.COMMA)) {
|
||||
return getSqlInjectField(field.split(SymbolConstant.COMMA));
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验表字段是否有效
|
||||
*
|
||||
* 字段定义只能是是字母 数字 下划线的组合(不允许有空格、转义字符串等)
|
||||
*/
|
||||
boolean isValidField = fieldPattern.matcher(field).matches();
|
||||
if (!isValidField) {
|
||||
String errorMsg = "字段不合法,存在SQL注入风险!--->" + field;
|
||||
log.error(errorMsg);
|
||||
throw new JeecgSqlInjectionException(errorMsg);
|
||||
}
|
||||
|
||||
//进一步验证是否存在SQL注入风险
|
||||
filterContent(field);
|
||||
return field;
|
||||
}
|
||||
|
||||
public static String getSqlInjectField(String... fields) {
|
||||
for (String s : fields) {
|
||||
getSqlInjectField(s);
|
||||
}
|
||||
return String.join(SymbolConstant.COMMA, fields);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -89,7 +153,7 @@ public class SqlInjectionUtil {
|
|||
if (value.indexOf(xssArr[i]) > -1) {
|
||||
log.error("请注意,存在SQL注入关键词---> {}", xssArr[i]);
|
||||
log.error("请注意,值可能存在SQL注入风险!---> {}", value);
|
||||
throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||
throw new JeecgSqlInjectionException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||
}
|
||||
}
|
||||
//update-begin-author:taoyan date:2022-7-13 for: 除了XSS_STR这些提前设置好的,还需要额外的校验比如 单引号
|
||||
|
@ -99,13 +163,13 @@ public class SqlInjectionUtil {
|
|||
if (value.indexOf(xssArr2[i]) > -1) {
|
||||
log.error("请注意,存在SQL注入关键词---> {}", xssArr2[i]);
|
||||
log.error("请注意,值可能存在SQL注入风险!---> {}", value);
|
||||
throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||
throw new JeecgSqlInjectionException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
//update-end-author:taoyan date:2022-7-13 for: 除了XSS_STR这些提前设置好的,还需要额外的校验比如 单引号
|
||||
if(Pattern.matches(SHOW_TABLES, value) || Pattern.matches(REGULAR_EXPRE_USER, value)){
|
||||
throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||
throw new JeecgSqlInjectionException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -114,7 +178,7 @@ public class SqlInjectionUtil {
|
|||
* sql注入过滤处理,遇到注入关键字抛异常
|
||||
* @param values
|
||||
*/
|
||||
public static void filterContent(String[] values) {
|
||||
public static void filterContent(String... values) {
|
||||
filterContent(values, null);
|
||||
}
|
||||
|
||||
|
@ -141,7 +205,7 @@ public class SqlInjectionUtil {
|
|||
if (value.indexOf(xssArr[i]) > -1) {
|
||||
log.error("请注意,存在SQL注入关键词---> {}", xssArr[i]);
|
||||
log.error("请注意,值可能存在SQL注入风险!---> {}", value);
|
||||
throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||
throw new JeecgSqlInjectionException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||
}
|
||||
}
|
||||
//update-begin-author:taoyan date:2022-7-13 for: 除了XSS_STR这些提前设置好的,还需要额外的校验比如 单引号
|
||||
|
@ -151,13 +215,13 @@ public class SqlInjectionUtil {
|
|||
if (value.indexOf(xssArr2[i]) > -1) {
|
||||
log.error("请注意,存在SQL注入关键词---> {}", xssArr2[i]);
|
||||
log.error("请注意,值可能存在SQL注入风险!---> {}", value);
|
||||
throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||
throw new JeecgSqlInjectionException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
//update-end-author:taoyan date:2022-7-13 for: 除了XSS_STR这些提前设置好的,还需要额外的校验比如 单引号
|
||||
if(Pattern.matches(SHOW_TABLES, value) || Pattern.matches(REGULAR_EXPRE_USER, value)){
|
||||
throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||
throw new JeecgSqlInjectionException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
@ -188,11 +252,11 @@ public class SqlInjectionUtil {
|
|||
if (value.indexOf(xssArr[i]) > -1 || value.startsWith(xssArr[i].trim())) {
|
||||
log.error("请注意,存在SQL注入关键词---> {}", xssArr[i]);
|
||||
log.error("请注意,值可能存在SQL注入风险!---> {}", value);
|
||||
throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||
throw new JeecgSqlInjectionException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||
}
|
||||
}
|
||||
if(Pattern.matches(SHOW_TABLES, value) || Pattern.matches(REGULAR_EXPRE_USER, value)){
|
||||
throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||
throw new JeecgSqlInjectionException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -222,12 +286,12 @@ public class SqlInjectionUtil {
|
|||
if (value.indexOf(xssArr[i]) > -1 || value.startsWith(xssArr[i].trim())) {
|
||||
log.error("请注意,存在SQL注入关键词---> {}", xssArr[i]);
|
||||
log.error("请注意,值可能存在SQL注入风险!---> {}", value);
|
||||
throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||
throw new JeecgSqlInjectionException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||
}
|
||||
}
|
||||
|
||||
if(Pattern.matches(SHOW_TABLES, value) || Pattern.matches(REGULAR_EXPRE_USER, value)){
|
||||
throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||
throw new JeecgSqlInjectionException("请注意,值可能存在SQL注入风险!--->" + value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -285,7 +349,7 @@ public class SqlInjectionUtil {
|
|||
if(matcher.find()){
|
||||
String error = "请注意,值可能存在SQL注入风险---> \\*.*\\";
|
||||
log.error(error);
|
||||
throw new RuntimeException(error);
|
||||
throw new JeecgSqlInjectionException(error);
|
||||
}
|
||||
|
||||
// issues/4737 sys/duplicate/check SQL注入 #4737
|
||||
|
@ -293,7 +357,7 @@ public class SqlInjectionUtil {
|
|||
if(sleepMatcher.find()){
|
||||
String error = "请注意,值可能存在SQL注入风险---> sleep";
|
||||
log.error(error);
|
||||
throw new RuntimeException(error);
|
||||
throw new JeecgSqlInjectionException(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.jeecg.common.util.security;
|
|||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.jeecg.common.exception.JeecgSqlInjectionException;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
|
@ -81,6 +82,12 @@ public abstract class AbstractQueryBlackListHandler {
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
// 返回黑名单校验结果(不合法直接抛出异常)
|
||||
if(!flag){
|
||||
log.error(this.getError());
|
||||
throw new JeecgSqlInjectionException(this.getError());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,24 +1,18 @@
|
|||
package org.jeecg.modules.system.controller;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.constant.SymbolConstant;
|
||||
import org.jeecg.common.util.SqlInjectionUtil;
|
||||
import org.jeecg.modules.system.mapper.SysDictMapper;
|
||||
import org.jeecg.modules.system.model.DuplicateCheckVo;
|
||||
import org.jeecg.modules.system.security.DictQueryBlackListHandler;
|
||||
import org.mybatis.spring.MyBatisSystemException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.modules.system.model.DuplicateCheckVo;
|
||||
import org.jeecg.modules.system.service.ISysDictService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* @Title: DuplicateCheckAction
|
||||
|
@ -34,10 +28,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||
public class DuplicateCheckController {
|
||||
|
||||
@Autowired
|
||||
SysDictMapper sysDictMapper;
|
||||
|
||||
@Autowired
|
||||
DictQueryBlackListHandler dictQueryBlackListHandler;
|
||||
ISysDictService sysDictService;
|
||||
|
||||
/**
|
||||
* 校验数据是否在系统中是否存在
|
||||
|
@ -47,14 +38,9 @@ public class DuplicateCheckController {
|
|||
@RequestMapping(value = "/check", method = RequestMethod.GET)
|
||||
@ApiOperation("重复校验接口")
|
||||
public Result<String> doDuplicateCheck(DuplicateCheckVo duplicateCheckVo, HttpServletRequest request) {
|
||||
Long num = null;
|
||||
|
||||
log.debug("----duplicate check------:"+ duplicateCheckVo.toString());
|
||||
//关联表字典(举例:sys_user,realname,id)
|
||||
//SQL注入校验(只限制非法串改数据库)
|
||||
final String[] sqlInjCheck = {duplicateCheckVo.getTableName(),duplicateCheckVo.getFieldName()};
|
||||
SqlInjectionUtil.filterContent(sqlInjCheck);
|
||||
// update-begin-author:taoyan date:20211227 for: JTC-25 【online报表】oracle 操作问题 录入弹框啥都不填直接保存 ①编码不是应该提示必填么?②报错也应该是具体文字提示,不是后台错误日志
|
||||
|
||||
// 1.填值为空,直接返回
|
||||
if(StringUtils.isEmpty(duplicateCheckVo.getFieldVal())){
|
||||
Result rs = new Result();
|
||||
rs.setCode(500);
|
||||
|
@ -62,31 +48,9 @@ public class DuplicateCheckController {
|
|||
rs.setMessage("数据为空,不作处理!");
|
||||
return rs;
|
||||
}
|
||||
//update-begin-author:taoyan date:20220329 for: VUEN-223【安全漏洞】当前被攻击的接口
|
||||
String checkSql = duplicateCheckVo.getTableName() + SymbolConstant.COMMA + duplicateCheckVo.getFieldName() + SymbolConstant.COMMA;
|
||||
if(!dictQueryBlackListHandler.isPass(checkSql)){
|
||||
return Result.error(dictQueryBlackListHandler.getError());
|
||||
}
|
||||
//update-end-author:taoyan date:20220329 for: VUEN-223【安全漏洞】当前被攻击的接口
|
||||
// update-end-author:taoyan date:20211227 for: JTC-25 【online报表】oracle 操作问题 录入弹框啥都不填直接保存 ①编码不是应该提示必填么?②报错也应该是具体文字提示,不是后台错误日志
|
||||
|
||||
// update-begin-author:liusq date:20230721 for: [issues/5134] duplicate/check Sql泄露问题
|
||||
try{
|
||||
if (StringUtils.isNotBlank(duplicateCheckVo.getDataId())) {
|
||||
// [2].编辑页面校验
|
||||
num = sysDictMapper.duplicateCheckCountSql(duplicateCheckVo);
|
||||
} else {
|
||||
// [1].添加页面校验
|
||||
num = sysDictMapper.duplicateCheckCountSqlNoDataId(duplicateCheckVo);
|
||||
}
|
||||
}catch(MyBatisSystemException e){
|
||||
log.error(e.getMessage(), e);
|
||||
String errorCause = "查询异常,请检查唯一校验的配置!";
|
||||
return Result.error(errorCause);
|
||||
}
|
||||
// update-end-author:liusq date:20230721 for: [issues/5134] duplicate/check Sql泄露问题
|
||||
|
||||
if (num == null || num == 0) {
|
||||
|
||||
// 2.返回结果
|
||||
if (sysDictService.duplicateCheckData(duplicateCheckVo)) {
|
||||
// 该值可用
|
||||
return Result.ok("该值可用!");
|
||||
} else {
|
||||
|
@ -95,21 +59,5 @@ public class DuplicateCheckController {
|
|||
return Result.error("该值不可用,系统中已存在!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* VUEN-2584【issue】平台sql注入漏洞几个问题
|
||||
* 部分特殊函数 可以将查询结果混夹在错误信息中,导致数据库的信息暴露
|
||||
* @param e
|
||||
* @return
|
||||
*/
|
||||
@ExceptionHandler(java.sql.SQLException.class)
|
||||
public Result<?> handleSQLException(Exception e){
|
||||
String msg = e.getMessage();
|
||||
String extractvalue = "extractvalue";
|
||||
String updatexml = "updatexml";
|
||||
if(msg!=null && (msg.toLowerCase().indexOf(extractvalue)>=0 || msg.toLowerCase().indexOf(updatexml)>=0)){
|
||||
return Result.error("校验失败,sql解析异常!");
|
||||
}
|
||||
return Result.error("校验失败,sql解析异常!" + msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -66,27 +66,6 @@ public interface SysDictMapper extends BaseMapper<SysDict> {
|
|||
*/
|
||||
public List<DictModelMany> queryDictItemsByCodeList(@Param("dictCodeList") List<String> dictCodeList);
|
||||
|
||||
/**
|
||||
* 通过查询指定table的 text code 获取字典
|
||||
* @param table
|
||||
* @param text
|
||||
* @param code
|
||||
* @return List<DictModel>
|
||||
*/
|
||||
@Deprecated
|
||||
public List<DictModel> queryTableDictItemsByCode(@Param("table") String table,@Param("text") String text,@Param("code") String code);
|
||||
|
||||
/**
|
||||
* 通过查询指定table的 text code 获取字典(指定查询条件)
|
||||
* @param table
|
||||
* @param text
|
||||
* @param code
|
||||
* @param filterSql
|
||||
* @return List<DictModel>
|
||||
*/
|
||||
@Deprecated
|
||||
public List<DictModel> queryTableDictItemsByCodeAndFilter(@Param("table") String table,@Param("text") String text,@Param("code") String code,@Param("filterSql") String filterSql);
|
||||
|
||||
/**
|
||||
* 通过查询指定table的 text code 获取字典
|
||||
* @param table
|
||||
|
@ -114,40 +93,6 @@ public interface SysDictMapper extends BaseMapper<SysDict> {
|
|||
*/
|
||||
List<DictModelMany> queryManyDictByKeys(@Param("dictCodeList") List<String> dictCodeList, @Param("keys") List<String> keys);
|
||||
|
||||
/**
|
||||
* 通过查询指定table的 text code key 获取字典值
|
||||
* @param table
|
||||
* @param text
|
||||
* @param code
|
||||
* @param key
|
||||
* @return String
|
||||
*/
|
||||
@Deprecated
|
||||
public String queryTableDictTextByKey(@Param("table") String table,@Param("text") String text,@Param("code") String code,@Param("key") String key);
|
||||
|
||||
// /**
|
||||
// * 通过查询指定table的 text code key 获取字典值,可批量查询
|
||||
// *
|
||||
// * @param table
|
||||
// * @param text
|
||||
// * @param code
|
||||
// * @param keys
|
||||
// * @return
|
||||
// */
|
||||
// @Deprecated
|
||||
// List<DictModel> queryTableDictTextByKeys(@Param("table") String table, @Param("text") String text, @Param("code") String code, @Param("keys") List<String> keys);
|
||||
|
||||
// D /**
|
||||
//// * 通过查询指定table的 text code key 获取字典值,包含value
|
||||
//// * @param table
|
||||
//// * @param text
|
||||
//// * @param code
|
||||
//// * @param keyArray
|
||||
//// * @return List<DictModel>
|
||||
//// */
|
||||
//// @Deprecated
|
||||
//// public List<DictModel> queryTableictByKeys(@Param("table") String table, @Param("text") String text, @Param("code") String code, @Param("keyArray") String[] keyArray);
|
||||
|
||||
/**
|
||||
* 查询所有部门 作为字典信息 id -->value,departName -->text
|
||||
* @return
|
||||
|
@ -160,29 +105,6 @@ public interface SysDictMapper extends BaseMapper<SysDict> {
|
|||
*/
|
||||
public List<DictModel> queryAllUserBackDictModel();
|
||||
|
||||
// /**
|
||||
// * 通过关键字查询出字典表
|
||||
// * @param table
|
||||
// * @param text
|
||||
// * @param code
|
||||
// * @param keyword
|
||||
// * @return
|
||||
// */
|
||||
// @Deprecated
|
||||
// public List<DictModel> queryTableDictItems(@Param("table") String table,@Param("text") String text,@Param("code") String code,@Param("keyword") String keyword);
|
||||
|
||||
|
||||
// /**
|
||||
// * 通过关键字查询出字典表
|
||||
// * @param page
|
||||
// * @param table
|
||||
// * @param text
|
||||
// * @param code
|
||||
// * @param keyword
|
||||
// * @return
|
||||
// */
|
||||
// //IPage<DictModel> queryTableDictItems(Page<DictModel> page, @Param("table") String table, @Param("text") String text, @Param("code") String code, @Param("keyword") String keyword);
|
||||
|
||||
/**
|
||||
* 根据表名、显示字段名、存储字段名 查询树
|
||||
* @param table
|
||||
|
@ -195,7 +117,7 @@ public interface SysDictMapper extends BaseMapper<SysDict> {
|
|||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
List<TreeSelectModel> queryTreeList(@Param("query") Map<String, String> query,@Param("table") String table,@Param("text") String text,@Param("code") String code,@Param("pidField") String pidField,@Param("pid") String pid,@Param("hasChildField") String hasChildField,@Param("converIsLeafVal") int converIsLeafVal);
|
||||
List<TreeSelectModel> queryTreeList(@Param("query") Map<String, String> query, @Param("table") String table, @Param("text") String text, @Param("code") String code, @Param("pidField") String pidField, @Param("pid") String pid, @Param("hasChildField") String hasChildField, @Param("converIsLeafVal") int converIsLeafVal);
|
||||
|
||||
/**
|
||||
* 删除
|
||||
|
@ -240,7 +162,7 @@ public interface SysDictMapper extends BaseMapper<SysDict> {
|
|||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
IPage<DictModel> queryTableDictWithFilter(Page<DictModel> page, @Param("table") String table, @Param("text") String text, @Param("code") String code, @Param("filterSql") String filterSql);
|
||||
IPage<DictModel> queryPageTableDictWithFilter(Page<DictModel> page, @Param("table") String table, @Param("text") String text, @Param("code") String code, @Param("filterSql") String filterSql);
|
||||
|
||||
/**
|
||||
* 查询 字典表数据 支持查询条件 查询所有
|
||||
|
@ -251,7 +173,7 @@ public interface SysDictMapper extends BaseMapper<SysDict> {
|
|||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
List<DictModel> queryAllTableDictItems(@Param("table") String table, @Param("text") String text, @Param("code") String code, @Param("filterSql") String filterSql);
|
||||
List<DictModel> queryTableDictWithFilter(@Param("table") String table, @Param("text") String text, @Param("code") String code, @Param("filterSql") String filterSql);
|
||||
|
||||
/**
|
||||
* 查询字典表的数据
|
||||
|
@ -262,7 +184,9 @@ public interface SysDictMapper extends BaseMapper<SysDict> {
|
|||
* @param codeValues 存储字段值 作为查询条件in
|
||||
* @return
|
||||
*/
|
||||
List<DictModel> queryTableDictByKeysAndFilterSql(@Param("table") String table, @Param("text") String text, @Param("code") String code, @Param("filterSql") String filterSql, @Param("codeValues") List<String> codeValues);
|
||||
@Deprecated
|
||||
List<DictModel> queryTableDictByKeysAndFilterSql(@Param("table") String table, @Param("text") String text, @Param("code") String code, @Param("filterSql") String filterSql,
|
||||
@Param("codeValues") List<String> codeValues);
|
||||
|
||||
/**
|
||||
* 根据应用id获取字典列表和详情
|
||||
|
|
|
@ -62,71 +62,35 @@
|
|||
)
|
||||
</select>
|
||||
|
||||
<!--通过查询指定table的 text code 获取字典-->
|
||||
<select id="queryTableDictItemsByCode" parameterType="String" resultType="org.jeecg.common.system.vo.DictModel">
|
||||
select ${text} as "text",${code} as "value" from ${table}
|
||||
</select>
|
||||
|
||||
<!--通过查询指定table的 text code 获取字典(指定查询条件)-->
|
||||
<select id="queryTableDictItemsByCodeAndFilter" parameterType="String" resultType="org.jeecg.common.system.vo.DictModel">
|
||||
select ${text} as "text",${code} as "value" from ${table}
|
||||
<if test="filterSql != null and filterSql != ''">
|
||||
where ${filterSql}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<!--通过查询指定table的 text code key 获取字典值-->
|
||||
<select id="queryTableDictTextByKey" parameterType="String" resultType="String">
|
||||
select ${text} as "text" from ${table} where ${code}= #{key}
|
||||
</select>
|
||||
|
||||
<!--通过查询指定table的 text code key 获取字典值,可批量查询
|
||||
<select id="queryTableDictTextByKeys" parameterType="String" resultType="org.jeecg.common.system.vo.DictModel">
|
||||
select ${text} as "text", ${code} as "value" from ${table} where ${code} IN (
|
||||
<foreach item="key" collection="keys" separator=",">
|
||||
#{key}
|
||||
</foreach>
|
||||
)
|
||||
</select>-->
|
||||
|
||||
<!--通过查询指定table的 text code key 获取字典值,包含value
|
||||
<select id="queryTableDictByKeys" parameterType="String" resultType="org.jeecg.common.system.vo.DictModel">
|
||||
select ${text} as "text", ${code} as "value" from ${table} where ${code} in
|
||||
<foreach item="key" collection="keyArray" open="(" separator="," close=")">
|
||||
#{key}
|
||||
</foreach>
|
||||
</select>-->
|
||||
|
||||
<!-- 重复校验 sql语句 -->
|
||||
<select id="duplicateCheckCountSql" resultType="Long" parameterType="org.jeecg.modules.system.model.DuplicateCheckVo">
|
||||
SELECT COUNT(*) FROM ${tableName} WHERE ${fieldName} = #{fieldVal} and id <> #{dataId}
|
||||
</select>
|
||||
|
||||
<!-- 重复校验 sql语句 -->
|
||||
<select id="duplicateCheckCountSqlNoDataId" resultType="Long" parameterType="org.jeecg.modules.system.model.DuplicateCheckVo">
|
||||
SELECT COUNT(*) FROM ${tableName} WHERE ${fieldName} = #{fieldVal}
|
||||
</select>
|
||||
|
||||
<!-- 查询部门信息 作为字典数据 -->
|
||||
<select id="queryAllDepartBackDictModel" resultType="org.jeecg.common.system.vo.DictModel">
|
||||
select id as "value",depart_name as "text" from sys_depart where del_flag = '0'
|
||||
</select>
|
||||
|
||||
<!-- 查询用户信息 作为字典数据 -->
|
||||
|
||||
<!-- 查询用户信息 作为字典数据 -->
|
||||
<select id="queryAllUserBackDictModel" resultType="org.jeecg.common.system.vo.DictModel">
|
||||
select username as "value",realname as "text" from sys_user where del_flag = '0'
|
||||
</select>
|
||||
|
||||
<!--通过查询指定table的 text code 获取字典数据,且支持关键字查询
|
||||
<select id="queryTableDictItems" parameterType="String" resultType="org.jeecg.common.system.vo.DictModel">
|
||||
select ${text} as "text",${code} as "value" from ${table} where ${text} like #{keyword}
|
||||
</select> -->
|
||||
|
||||
<!-- 根据表名、显示字段名、存储字段名、父ID查询树 -->
|
||||
<!-- *****************以下方法写法存在SQL注入风险***************** -->
|
||||
|
||||
<!-- 重复校验 sql语句【已加入SQL注入check】 -->
|
||||
<sql id="checkDuplicateCountSqlFragment">
|
||||
SELECT COUNT(1) FROM ${tableName} WHERE ${fieldName} = #{fieldVal}
|
||||
</sql>
|
||||
<select id="duplicateCheckCountSql" resultType="Long" parameterType="org.jeecg.modules.system.model.DuplicateCheckVo">
|
||||
<include refid="checkDuplicateCountSqlFragment"></include>
|
||||
AND id <> #{dataId}
|
||||
</select>
|
||||
<select id="duplicateCheckCountSqlNoDataId" resultType="Long" parameterType="org.jeecg.modules.system.model.DuplicateCheckVo">
|
||||
<include refid="checkDuplicateCountSqlFragment"></include>
|
||||
</select>
|
||||
|
||||
<!-- 根据表名、显示字段名、存储字段名、父ID查询树 【已加入SQL注入check】 -->
|
||||
<select id="queryTreeList" parameterType="Object" resultType="org.jeecg.modules.system.model.TreeSelectModel">
|
||||
select ${text} as "title",
|
||||
${code} as "key",
|
||||
<!-- udapte-begin-author:taoyan date:20211115 for: 自定义树控件只显示父节点,子节点无法展开 (此处还原不可再改) /issues/I4HZAL -->
|
||||
<if test="hasChildField != null and hasChildField != ''">
|
||||
<choose>
|
||||
<when test="converIsLeafVal!=null and converIsLeafVal==1">
|
||||
|
@ -137,11 +101,10 @@
|
|||
</otherwise>
|
||||
</choose>
|
||||
</if>
|
||||
<!-- udapte-end-author:taoyan date:20211115 for: 自定义树控件只显示父节点,子节点无法展开 (此处还原不可再改) /issues/I4HZAL -->
|
||||
${pidField} as parentId
|
||||
from ${table}
|
||||
where
|
||||
<!-- udapte-begin-author:sunjianlei date:20220110 for: 【JTC-597】自定义树查询条件查不出数据 -->
|
||||
<!-- 父ID条件 -->
|
||||
<if test="query == null">
|
||||
<choose>
|
||||
<when test="pid != null and pid != ''">
|
||||
|
@ -152,6 +115,7 @@
|
|||
</otherwise>
|
||||
</choose>
|
||||
</if>
|
||||
<!-- 查询条件组装 -->
|
||||
<if test="query!= null">
|
||||
1 = 1
|
||||
<foreach collection="query.entrySet()" item="value" index="key" >
|
||||
|
@ -164,7 +128,7 @@
|
|||
</otherwise>
|
||||
</choose>
|
||||
</foreach>
|
||||
<!-- udapte-end-author:sunjianlei date:20220615 for: 【issues/3709】自定义树查询条件没有处理父ID,没有树状结构了 -->
|
||||
<!-- 【issues/3709】自定义树查询条件没有处理父ID,没有树状结构了 -->
|
||||
<choose>
|
||||
<when test="pid != null and pid != ''">
|
||||
and ${pidField} = #{pid}
|
||||
|
@ -173,45 +137,42 @@
|
|||
and (${pidField} = '' OR ${pidField} IS NULL)
|
||||
</otherwise>
|
||||
</choose>
|
||||
<!-- udapte-end-author:sunjianlei date:20220615 for: 【issues/3709】自定义树查询条件没有处理父ID,没有树状结构了 -->
|
||||
</if>
|
||||
<!-- udapte-end-author:sunjianlei date:20220110 for: 【JTC-597】自定义树查询条件查不出数据 -->
|
||||
</select>
|
||||
|
||||
|
||||
<!-- 分页查询字典表数据 -->
|
||||
<!-- 分页查询字典表数据,支持text或code模糊查询匹配【已加入SQL注入check】 -->
|
||||
<select id="queryDictTablePageList" parameterType="Object" resultType="org.jeecg.common.system.vo.DictModel">
|
||||
select ${query.text} as "text",${query.code} as "value" from ${query.table}
|
||||
where 1 = 1
|
||||
select ${query.text} as "text", ${query.code} as "value" from ${query.table}
|
||||
where
|
||||
<if test="query.keyword != null and query.keyword != ''">
|
||||
<bind name="bindKeyword" value="'%'+query.keyword+'%'"/>
|
||||
and (${query.text} like #{bindKeyword} or ${query.code} like #{bindKeyword})
|
||||
(${query.text} like #{bindKeyword} or ${query.code} like #{bindKeyword})
|
||||
</if>
|
||||
<if test="query.codeValue != null and query.codeValue != ''">
|
||||
and ${query.code} = #{query.codeValue}
|
||||
${query.code} = #{query.codeValue}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<!--通过查询指定table的 text code 获取字典数据,且支持关键字和自定义查询条件查询 分页-->
|
||||
|
||||
<!--查询表字典数据,支持关键字和自定义查询条件【已加入SQL注入check】 -->
|
||||
<sql id="queryTableDictWithFilterSqlFragment">
|
||||
select ${text} as "text", ${code} as "value" from ${table}
|
||||
<if test="filterSql != null and filterSql != ''">
|
||||
where ${filterSql}
|
||||
</if>
|
||||
</sql>
|
||||
<!--查询表字典数据,分页返回-->
|
||||
<select id="queryPageTableDictWithFilter" parameterType="String" resultType="org.jeecg.common.system.vo.DictModel">
|
||||
<include refid="queryTableDictWithFilterSqlFragment"></include>
|
||||
</select>
|
||||
<!--查询表字典数据,不分页返回-->
|
||||
<select id="queryTableDictWithFilter" parameterType="String" resultType="org.jeecg.common.system.vo.DictModel">
|
||||
select ${text} as "text", ${code} as "value" from ${table}
|
||||
<if test="filterSql != null and filterSql != ''">
|
||||
${filterSql}
|
||||
</if>
|
||||
<include refid="queryTableDictWithFilterSqlFragment"></include>
|
||||
</select>
|
||||
|
||||
<!--通过查询指定table的 text code 获取字典数据,且支持关键字和自定义查询条件查询 获取所有 -->
|
||||
<select id="queryAllTableDictItems" parameterType="String" resultType="org.jeecg.common.system.vo.DictModel">
|
||||
select ${text} as "text", ${code} as "value" from ${table}
|
||||
<if test="filterSql != null and filterSql != ''">
|
||||
${filterSql}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
|
||||
<!-- 查询字典表的数据 支持设置过滤条件、设置存储值作为in查询条件 -->
|
||||
<!-- 查询表字典的数据, 支持设置过滤条件和code值 精确匹配查询【已加入SQL注入check】 -->
|
||||
<select id="queryTableDictByKeysAndFilterSql" parameterType="String" resultType="org.jeecg.common.system.vo.DictModel">
|
||||
select ${text} as "text", ${code} as "value" from ${table} where ${code} IN (
|
||||
select ${text} as "text", ${code} as "value" from ${table}
|
||||
where ${code} IN (
|
||||
<foreach item="key" collection="codeValues" separator=",">
|
||||
#{key}
|
||||
</foreach>
|
||||
|
@ -221,6 +182,8 @@
|
|||
</if>
|
||||
</select>
|
||||
|
||||
<!-- *****************以上方法写法存在SQL注入风险***************** -->
|
||||
|
||||
<!--根据应用id获取字典列表和详情-->
|
||||
<select id="getDictListByLowAppId" resultType="org.jeecg.modules.system.entity.SysDict">
|
||||
select id,dict_name,dict_code from sys_dict
|
||||
|
|
|
@ -5,6 +5,7 @@ import org.jeecg.common.system.vo.DictModel;
|
|||
import org.jeecg.common.system.vo.DictQuery;
|
||||
import org.jeecg.modules.system.entity.SysDict;
|
||||
import org.jeecg.modules.system.entity.SysDictItem;
|
||||
import org.jeecg.modules.system.model.DuplicateCheckVo;
|
||||
import org.jeecg.modules.system.model.TreeSelectModel;
|
||||
import org.jeecg.modules.system.vo.lowapp.SysDictVo;
|
||||
|
||||
|
@ -21,6 +22,15 @@ import java.util.Map;
|
|||
*/
|
||||
public interface ISysDictService extends IService<SysDict> {
|
||||
|
||||
/**
|
||||
* 校验数据是否可用,不存在重复数据
|
||||
*
|
||||
* @param duplicateCheckVo
|
||||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean duplicateCheckData(DuplicateCheckVo duplicateCheckVo);
|
||||
|
||||
/**
|
||||
* 通过字典code获取字典数据
|
||||
* @param code
|
||||
|
@ -51,13 +61,13 @@ public interface ISysDictService extends IService<SysDict> {
|
|||
|
||||
/**
|
||||
* 查通过查询指定table的 text code 获取字典
|
||||
* @param table
|
||||
* @param tableFilterSql
|
||||
* @param text
|
||||
* @param code
|
||||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
List<DictModel> queryTableDictItemsByCode(String table, String text, String code);
|
||||
List<DictModel> queryTableDictItemsByCode(String tableFilterSql, String text, String code);
|
||||
|
||||
/**
|
||||
* 通过查询指定table的 text code 获取字典(指定查询条件)
|
||||
|
@ -206,7 +216,7 @@ public interface ISysDictService extends IService<SysDict> {
|
|||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
List<TreeSelectModel> queryTreeList(Map<String, String> query,String table, String text, String code, String pidField,String pid,String hasChildField,int converIsLeafVal);
|
||||
List<TreeSelectModel> queryTreeList(Map<String, String> query, String table, String text, String code, String pidField, String pid, String hasChildField, int converIsLeafVal);
|
||||
|
||||
/**
|
||||
* 真实删除
|
||||
|
@ -235,7 +245,7 @@ public interface ISysDictService extends IService<SysDict> {
|
|||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
public List<DictModel> queryDictTablePageList(DictQuery query,int pageSize, int pageNo);
|
||||
public List<DictModel> queryDictTablePageList(DictQuery query, int pageSize, int pageNo);
|
||||
|
||||
/**
|
||||
* 获取字典数据
|
||||
|
|
|
@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
|||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.jeecg.common.config.TenantContext;
|
||||
import org.jeecg.common.constant.CacheConstant;
|
||||
import org.jeecg.common.constant.CommonConstant;
|
||||
|
@ -13,7 +14,6 @@ import org.jeecg.common.constant.DataBaseConstant;
|
|||
import org.jeecg.common.constant.SymbolConstant;
|
||||
import org.jeecg.common.exception.JeecgBootException;
|
||||
import org.jeecg.common.system.query.QueryGenerator;
|
||||
import org.jeecg.common.system.util.JwtUtil;
|
||||
import org.jeecg.common.system.util.ResourceUtil;
|
||||
import org.jeecg.common.system.vo.DictModel;
|
||||
import org.jeecg.common.system.vo.DictModelMany;
|
||||
|
@ -25,14 +25,18 @@ import org.jeecg.modules.system.entity.SysDict;
|
|||
import org.jeecg.modules.system.entity.SysDictItem;
|
||||
import org.jeecg.modules.system.mapper.SysDictItemMapper;
|
||||
import org.jeecg.modules.system.mapper.SysDictMapper;
|
||||
import org.jeecg.modules.system.model.DuplicateCheckVo;
|
||||
import org.jeecg.modules.system.model.TreeSelectModel;
|
||||
import org.jeecg.modules.system.security.DictQueryBlackListHandler;
|
||||
import org.jeecg.modules.system.service.ISysDictService;
|
||||
import org.jeecg.modules.system.vo.lowapp.SysDictVo;
|
||||
import org.mybatis.spring.MyBatisSystemException;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -53,6 +57,53 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
|
|||
private SysDictMapper sysDictMapper;
|
||||
@Autowired
|
||||
private SysDictItemMapper sysDictItemMapper;
|
||||
@Autowired
|
||||
private DictQueryBlackListHandler dictQueryBlackListHandler;
|
||||
|
||||
@Override
|
||||
public boolean duplicateCheckData(DuplicateCheckVo duplicateCheckVo) {
|
||||
Long count = null;
|
||||
|
||||
// 1.针对采用 ${}写法的表名和字段进行转义和check
|
||||
String table = SqlInjectionUtil.getSqlInjectTableName(duplicateCheckVo.getTableName());
|
||||
String fieldName = SqlInjectionUtil.getSqlInjectField(duplicateCheckVo.getFieldName());
|
||||
duplicateCheckVo.setTableName(table);
|
||||
duplicateCheckVo.setFieldName(fieldName);
|
||||
|
||||
// 2.SQL注入check(只限制非法串改数据库)
|
||||
//关联表字典(举例:sys_user,realname,id)
|
||||
SqlInjectionUtil.filterContent(table, fieldName);
|
||||
|
||||
// 3.表字典黑名单check
|
||||
String checkSql = table + SymbolConstant.COMMA + fieldName + SymbolConstant.COMMA;
|
||||
dictQueryBlackListHandler.isPass(checkSql);
|
||||
|
||||
// 4.执行SQL 查询是否存在值
|
||||
try{
|
||||
if (StringUtils.isNotBlank(duplicateCheckVo.getDataId())) {
|
||||
// [1].编辑页面校验
|
||||
count = sysDictMapper.duplicateCheckCountSql(duplicateCheckVo);
|
||||
} else {
|
||||
// [2].添加页面校验
|
||||
count = sysDictMapper.duplicateCheckCountSqlNoDataId(duplicateCheckVo);
|
||||
}
|
||||
}catch(MyBatisSystemException e){
|
||||
log.error(e.getMessage(), e);
|
||||
String errorCause = "查询异常,请检查唯一校验的配置!";
|
||||
throw new JeecgBootException(errorCause);
|
||||
}
|
||||
|
||||
// 4.返回结果
|
||||
if (count == null || count == 0) {
|
||||
// 该值可用
|
||||
return true;
|
||||
} else {
|
||||
// 该值不可用
|
||||
log.info("该值不可用,系统中已存在!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 通过查询指定code 获取字典
|
||||
|
@ -152,22 +203,69 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
|
|||
/**
|
||||
* 通过查询指定table的 text code 获取字典
|
||||
* dictTableCache采用redis缓存有效期10分钟
|
||||
* @param table
|
||||
* @param tableFilterSql
|
||||
* @param text
|
||||
* @param code
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
//@Cacheable(value = CacheConstant.SYS_DICT_TABLE_CACHE)
|
||||
public List<DictModel> queryTableDictItemsByCode(String table, String text, String code) {
|
||||
@Deprecated
|
||||
public List<DictModel> queryTableDictItemsByCode(String tableFilterSql, String text, String code) {
|
||||
log.debug("无缓存dictTableList的时候调用这里!");
|
||||
return sysDictMapper.queryTableDictItemsByCode(table,text,code);
|
||||
|
||||
// 1.表字典黑名单check
|
||||
String str = tableFilterSql+","+text+","+code;
|
||||
if(!dictQueryBlackListHandler.isPass(str)){
|
||||
log.error(dictQueryBlackListHandler.getError());
|
||||
return null;
|
||||
}
|
||||
|
||||
// 2.分割SQL获取表名和条件
|
||||
String table = null;
|
||||
String filterSql = null;
|
||||
if(tableFilterSql.toLowerCase().indexOf(DataBaseConstant.SQL_WHERE)>0){
|
||||
String[] arr = tableFilterSql.split(" (?i)where ");
|
||||
table = arr[0];
|
||||
filterSql = oConvertUtils.getString(arr[1], null);
|
||||
}else{
|
||||
table = tableFilterSql;
|
||||
}
|
||||
|
||||
// 3.SQL注入check
|
||||
SqlInjectionUtil.filterContent(table, text, code);
|
||||
SqlInjectionUtil.specialFilterContentForDictSql(filterSql);
|
||||
|
||||
// 4.针对采用 ${}写法的表名和字段进行转义和check
|
||||
table = SqlInjectionUtil.getSqlInjectTableName(table);
|
||||
text = SqlInjectionUtil.getSqlInjectField(text);
|
||||
code = SqlInjectionUtil.getSqlInjectField(code);
|
||||
|
||||
//return sysDictMapper.queryTableDictItemsByCode(tableFilterSql,text,code);
|
||||
return sysDictMapper.queryTableDictWithFilter(table,text,code,filterSql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DictModel> queryTableDictItemsByCodeAndFilter(String table, String text, String code, String filterSql) {
|
||||
log.debug("无缓存dictTableList的时候调用这里!");
|
||||
return sysDictMapper.queryTableDictItemsByCodeAndFilter(table,text,code,filterSql);
|
||||
|
||||
// 1.SQL注入校验(只限制非法串改数据库)
|
||||
SqlInjectionUtil.specialFilterContentForDictSql(table);
|
||||
SqlInjectionUtil.filterContent(text, code);
|
||||
SqlInjectionUtil.specialFilterContentForDictSql(filterSql);
|
||||
|
||||
// 2.表字典黑名单 Check
|
||||
String str = table+","+text+","+code;
|
||||
if(!dictQueryBlackListHandler.isPass(str)){
|
||||
log.error(dictQueryBlackListHandler.getError());
|
||||
return null;
|
||||
}
|
||||
|
||||
// 3.针对采用 ${}写法的表名和字段进行转义和check
|
||||
table = SqlInjectionUtil.getSqlInjectTableName(table);
|
||||
text = SqlInjectionUtil.getSqlInjectField(text);
|
||||
code = SqlInjectionUtil.getSqlInjectField(code);
|
||||
|
||||
return sysDictMapper.queryTableDictWithFilter(table,text,code,filterSql);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -183,27 +281,70 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
|
|||
@Cacheable(value = CacheConstant.SYS_DICT_TABLE_CACHE, unless = "#result == null ")
|
||||
public String queryTableDictTextByKey(String table,String text,String code, String key) {
|
||||
log.debug("无缓存dictTable的时候调用这里!");
|
||||
return sysDictMapper.queryTableDictTextByKey(table,text,code,key);
|
||||
|
||||
// 1.表字典黑名单check
|
||||
String str = table+","+text+","+code;
|
||||
if(!dictQueryBlackListHandler.isPass(str)){
|
||||
log.error(dictQueryBlackListHandler.getError());
|
||||
return null;
|
||||
}
|
||||
// 2.sql注入check
|
||||
SqlInjectionUtil.filterContent(table, text, code, key);
|
||||
|
||||
// 3.针对采用 ${}写法的表名和字段进行转义和check
|
||||
table = SqlInjectionUtil.getSqlInjectTableName(table);
|
||||
text = SqlInjectionUtil.getSqlInjectField(text);
|
||||
code = SqlInjectionUtil.getSqlInjectField(code);
|
||||
|
||||
List<DictModel> dictModeList = sysDictMapper.queryTableDictByKeysAndFilterSql(table, text, code, null, Arrays.asList(key));
|
||||
if(CollectionUtils.isEmpty(dictModeList)){
|
||||
return null;
|
||||
}else{
|
||||
return dictModeList.get(0).getText();
|
||||
}
|
||||
|
||||
//此方法删除(20230902)
|
||||
//return sysDictMapper.queryTableDictTextByKey(table,text,code,key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DictModel> queryTableDictTextByKeys(String table, String text, String code, List<String> keys) {
|
||||
//update-begin-author:taoyan date:20220113 for: @dict注解支持 dicttable 设置where条件
|
||||
public List<DictModel> queryTableDictTextByKeys(String table, String text, String code, List<String> codeValues) {
|
||||
// 1.表字典黑名单check
|
||||
String str = table+","+text+","+code;
|
||||
if(!dictQueryBlackListHandler.isPass(str)){
|
||||
log.error(dictQueryBlackListHandler.getError());
|
||||
return null;
|
||||
}
|
||||
|
||||
// 2.分割SQL获取表名和条件
|
||||
String filterSql = null;
|
||||
if(table.toLowerCase().indexOf(DataBaseConstant.SQL_WHERE)>0){
|
||||
String[] arr = table.split(" (?i)where ");
|
||||
table = arr[0];
|
||||
filterSql = arr[1];
|
||||
}
|
||||
String[] tableAndFields = new String[]{table, text, code};
|
||||
SqlInjectionUtil.filterContent(tableAndFields);
|
||||
|
||||
// 3.SQL注入check
|
||||
SqlInjectionUtil.filterContent(table, text, code);
|
||||
SqlInjectionUtil.specialFilterContentForDictSql(filterSql);
|
||||
return sysDictMapper.queryTableDictByKeysAndFilterSql(table, text, code, filterSql, keys);
|
||||
|
||||
// 4.针对采用 ${}写法的表名和字段进行转义和check
|
||||
table = SqlInjectionUtil.getSqlInjectTableName(table);
|
||||
text = SqlInjectionUtil.getSqlInjectField(text);
|
||||
code = SqlInjectionUtil.getSqlInjectField(code);
|
||||
|
||||
return sysDictMapper.queryTableDictByKeysAndFilterSql(table, text, code, filterSql, codeValues);
|
||||
//update-end-author:taoyan date:20220113 for: @dict注解支持 dicttable 设置where条件
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> queryTableDictByKeys(String table, String text, String code, String keys) {
|
||||
String str = table+","+text+","+code;
|
||||
if(!dictQueryBlackListHandler.isPass(str)){
|
||||
log.error(dictQueryBlackListHandler.getError());
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.queryTableDictByKeys(table, text, code, keys, true);
|
||||
}
|
||||
|
||||
|
@ -213,46 +354,56 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
|
|||
* @param table
|
||||
* @param text
|
||||
* @param code
|
||||
* @param keys (逗号分隔)
|
||||
* @param codeValuesStr (逗号分隔)
|
||||
* @param delNotExist 是否移除不存在的项,默认为true,设为false如果某个key不存在数据库中,则直接返回key本身
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
//update-begin--Author:lvdandan Date:20201204 for:JT-36【online】树形列表bug修改后,还是显示原来值 暂时去掉缓存
|
||||
//@Cacheable(value = CacheConstant.SYS_DICT_TABLE_BY_KEYS_CACHE)
|
||||
//update-end--Author:lvdandan Date:20201204 for:JT-36【online】树形列表bug修改后,还是显示原来值 暂时去掉缓存
|
||||
public List<String> queryTableDictByKeys(String table, String text, String code, String keys, boolean delNotExist) {
|
||||
if(oConvertUtils.isEmpty(keys)){
|
||||
public List<String> queryTableDictByKeys(String table, String text, String code, String codeValuesStr, boolean delNotExist) {
|
||||
if(oConvertUtils.isEmpty(codeValuesStr)){
|
||||
return null;
|
||||
}
|
||||
String[] keyArray = keys.split(",");
|
||||
|
||||
//update-begin-author:taoyan date:2022-4-24 for: 下拉搜索组件,表单编辑页面回显下拉搜索的文本的时候,因为表名后配置了条件,导致sql执行失败,
|
||||
//1.分割sql获取表名 和 条件sql
|
||||
String filterSql = null;
|
||||
if(table.toLowerCase().indexOf("where")!=-1){
|
||||
String[] arr = table.split(" (?i)where ");
|
||||
table = arr[0];
|
||||
filterSql = arr[1];
|
||||
}
|
||||
String[] tableAndFields = new String[]{table, text, code};
|
||||
SqlInjectionUtil.filterContent(tableAndFields);
|
||||
SqlInjectionUtil.specialFilterContentForDictSql(filterSql);
|
||||
List<DictModel> dicts = sysDictMapper.queryTableDictByKeysAndFilterSql(table, text, code, filterSql, Arrays.asList(keyArray));
|
||||
//update-end-author:taoyan date:2022-4-24 for: 下拉搜索组件,表单编辑页面回显下拉搜索的文本的时候,因为表名后配置了条件,导致sql执行失败,
|
||||
List<String> texts = new ArrayList<>(dicts.size());
|
||||
|
||||
// update-begin--author:sunjianlei--date:20210514--for:新增delNotExist参数,设为false不删除数据库里不存在的key ----
|
||||
// 查询出来的顺序可能是乱的,需要排个序
|
||||
for (String key : keyArray) {
|
||||
List<DictModel> res = dicts.stream().filter(i -> key.equals(i.getValue())).collect(Collectors.toList());
|
||||
// 2.SQL注入check
|
||||
SqlInjectionUtil.filterContent(table, text, code);
|
||||
SqlInjectionUtil.specialFilterContentForDictSql(filterSql);
|
||||
|
||||
// 3.表字典黑名单check
|
||||
String str = table+","+text+","+code;
|
||||
if(!dictQueryBlackListHandler.isPass(str)){
|
||||
log.error(dictQueryBlackListHandler.getError());
|
||||
return null;
|
||||
}
|
||||
|
||||
// 4.针对采用 ${}写法的表名和字段进行转义和check
|
||||
table = SqlInjectionUtil.getSqlInjectTableName(table);
|
||||
text = SqlInjectionUtil.getSqlInjectField(text);
|
||||
code = SqlInjectionUtil.getSqlInjectField(code);
|
||||
|
||||
//字典条件值
|
||||
String[] codeValues = codeValuesStr.split(",");
|
||||
// 5.查询字典数据
|
||||
List<DictModel> dicts = sysDictMapper.queryTableDictByKeysAndFilterSql(SqlInjectionUtil.getSqlInjectTableName(table),
|
||||
SqlInjectionUtil.getSqlInjectField(text), SqlInjectionUtil.getSqlInjectField(code), filterSql, Arrays.asList(codeValues));
|
||||
|
||||
List<String> texts = new ArrayList<>(dicts.size());
|
||||
// 6.查询出来的顺序可能是乱的,需要排个序
|
||||
for (String conditionalVal : codeValues) {
|
||||
List<DictModel> res = dicts.stream().filter(i -> conditionalVal.equals(i.getValue())).collect(Collectors.toList());
|
||||
if (res.size() > 0) {
|
||||
texts.add(res.get(0).getText());
|
||||
} else if (!delNotExist) {
|
||||
texts.add(key);
|
||||
texts.add(conditionalVal);
|
||||
}
|
||||
}
|
||||
// update-end--author:sunjianlei--date:20210514--for:新增delNotExist参数,设为false不删除数据库里不存在的key ----
|
||||
|
||||
return texts;
|
||||
}
|
||||
|
||||
|
@ -308,12 +459,18 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
|
|||
public List<DictModel> queryLittleTableDictItems(String table, String text, String code, String condition, String keyword, int pageSize) {
|
||||
Page<DictModel> page = new Page<DictModel>(1, pageSize);
|
||||
page.setSearchCount(false);
|
||||
|
||||
//为了防止sql(jeecg提供了防注入的方法,可以在拼接 SQL 语句时自动对参数进行转义,避免SQL注入攻击)
|
||||
// 1. 针对采用 ${}写法的表名和字段进行转义和check
|
||||
table = SqlInjectionUtil.getSqlInjectTableName(table);
|
||||
text = SqlInjectionUtil.getSqlInjectField(text);
|
||||
code = SqlInjectionUtil.getSqlInjectField(code);
|
||||
|
||||
//【issues/3713】字典接口存在SQL注入风险
|
||||
SqlInjectionUtil.specialFilterContentForDictSql(code);
|
||||
|
||||
// 2. 查询条件SQL (获取条件sql方法含sql注入校验)
|
||||
String filterSql = getFilterSql(table, text, code, condition, keyword);
|
||||
IPage<DictModel> pageList = baseMapper.queryTableDictWithFilter(page, table, text, code, filterSql);
|
||||
|
||||
// 3. 返回表字典数据
|
||||
IPage<DictModel> pageList = baseMapper.queryPageTableDictWithFilter(page, table, text, code, filterSql);
|
||||
return pageList.getRecords();
|
||||
}
|
||||
|
||||
|
@ -326,14 +483,16 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
|
|||
* @return
|
||||
*/
|
||||
private String getFilterSql(String table, String text, String code, String condition, String keyword){
|
||||
String keywordSql = null, filterSql = "", sqlWhere = " where ";
|
||||
// update-begin-author:sunjianlei date:20220112 for: 【JTC-631】判断如果 table 携带了 where 条件,那么就使用 and 查询,防止报错
|
||||
String filterSql = "";
|
||||
String keywordSql = null;
|
||||
String sqlWhere = "where ";
|
||||
|
||||
//【JTC-631】判断如果 table 携带了 where 条件,那么就使用 and 查询,防止报错
|
||||
if (table.toLowerCase().contains(sqlWhere)) {
|
||||
sqlWhere = " and ";
|
||||
}
|
||||
// update-end-author:sunjianlei date:20220112 for: 【JTC-631】判断如果 table 携带了 where 条件,那么就使用 and 查询,防止报错
|
||||
|
||||
//update-begin-author:taoyan date:2022-8-15 for: 下拉搜索组件 支持传入排序信息 查询排序
|
||||
// 下拉搜索组件 支持传入排序信息 查询排序
|
||||
String orderField = "", orderType = "";
|
||||
if (oConvertUtils.isNotEmpty(keyword)) {
|
||||
// 关键字里面如果写入了 排序信息 xxxxx[orderby:create_time,desc]
|
||||
|
@ -358,7 +517,8 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
|
|||
}
|
||||
}
|
||||
}
|
||||
//update-end-author:taoyan date:2022-8-15 for: 下拉搜索组件 支持传入排序信息 查询排序
|
||||
|
||||
//下拉搜索组件 支持传入排序信息 查询排序
|
||||
if(oConvertUtils.isNotEmpty(condition) && oConvertUtils.isNotEmpty(keywordSql)){
|
||||
filterSql+= sqlWhere + condition + " and " + keywordSql;
|
||||
}else if(oConvertUtils.isNotEmpty(condition)){
|
||||
|
@ -366,24 +526,68 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
|
|||
}else if(oConvertUtils.isNotEmpty(keywordSql)){
|
||||
filterSql+= sqlWhere + keywordSql;
|
||||
}
|
||||
//update-begin-author:taoyan date:2022-8-15 for: 下拉搜索组件 支持传入排序信息 查询排序
|
||||
|
||||
// 增加排序逻辑
|
||||
if (oConvertUtils.isNotEmpty(orderField)) {
|
||||
filterSql += " order by " + orderField + " " + orderType;
|
||||
}
|
||||
//update-end-author:taoyan date:2022-8-15 for: 下拉搜索组件 支持传入排序信息 查询排序
|
||||
return filterSql;
|
||||
|
||||
// result.1 返回条件SQL(去掉 where 关键词)
|
||||
final String wherePattern = "(?i)where "; // (?i) 表示不区分大小写
|
||||
String filterSqlString = filterSql.trim().replaceAll(wherePattern, "");
|
||||
|
||||
// result.2 条件SQL进行漏洞 check
|
||||
SqlInjectionUtil.specialFilterContentForDictSql(filterSqlString);
|
||||
|
||||
return filterSqlString;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<DictModel> queryAllTableDictItems(String table, String text, String code, String condition, String keyword) {
|
||||
// 1.获取条件sql
|
||||
String filterSql = getFilterSql(table, text, code, condition, keyword);
|
||||
List<DictModel> ls = baseMapper.queryAllTableDictItems(table, text, code, filterSql);
|
||||
|
||||
// 为了防止sql(jeecg提供了防注入的方法,可以在拼接 SQL 语句时自动对参数进行转义,避免SQL注入攻击)
|
||||
// 2.针对采用 ${}写法的表名和字段进行转义和check
|
||||
table = SqlInjectionUtil.getSqlInjectTableName(table);
|
||||
text = SqlInjectionUtil.getSqlInjectField(text);
|
||||
code = SqlInjectionUtil.getSqlInjectField(code);
|
||||
|
||||
List<DictModel> ls = baseMapper.queryTableDictWithFilter(table, text, code, filterSql);
|
||||
return ls;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TreeSelectModel> queryTreeList(Map<String, String> query,String table, String text, String code, String pidField,String pid,String hasChildField,int converIsLeafVal) {
|
||||
return baseMapper.queryTreeList(query, table, text, code, pidField, pid, hasChildField,converIsLeafVal);
|
||||
public List<TreeSelectModel> queryTreeList(Map<String, String> query, String table, String text, String code, String pidField, String pid, String hasChildField, int converIsLeafVal) {
|
||||
//为了防止sql(jeecg提供了防注入的方法,可以在拼接 SQL 语句时自动对参数进行转义,避免SQL注入攻击)
|
||||
// 1.针对采用 ${}写法的表名和字段进行转义和check
|
||||
table = SqlInjectionUtil.getSqlInjectTableName(table);
|
||||
text = SqlInjectionUtil.getSqlInjectField(text);
|
||||
code = SqlInjectionUtil.getSqlInjectField(code);
|
||||
pidField = SqlInjectionUtil.getSqlInjectField(pidField);
|
||||
hasChildField = SqlInjectionUtil.getSqlInjectField(hasChildField);
|
||||
|
||||
// 2.检测最终SQL是否存在SQL注入风险
|
||||
String dictCode = table + "," + text + "," + code;
|
||||
SqlInjectionUtil.filterContent(dictCode);
|
||||
|
||||
// 3.表字典SQL表名黑名单 Check
|
||||
if(!dictQueryBlackListHandler.isPass(dictCode)){
|
||||
log.error("Sql异常:{}", dictQueryBlackListHandler.getError());
|
||||
return null;
|
||||
}
|
||||
// 4.检测查询条件是否存在SQL注入
|
||||
Map<String, String> queryParams = null;
|
||||
if (query != null) {
|
||||
queryParams = new HashMap<>(5);
|
||||
for (Map.Entry<String, String> searchItem : query.entrySet()) {
|
||||
String fieldName = searchItem.getKey();
|
||||
queryParams.put(SqlInjectionUtil.getSqlInjectField(fieldName), searchItem.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
return baseMapper.queryTreeList(queryParams, table, text, code, pidField, pid, hasChildField, converIsLeafVal);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -405,6 +609,26 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
|
|||
@Override
|
||||
public List<DictModel> queryDictTablePageList(DictQuery query, int pageSize, int pageNo) {
|
||||
Page page = new Page(pageNo,pageSize,false);
|
||||
|
||||
//为了防止sql(jeecg提供了防注入的方法,可以在拼接 SQL 语句时自动对参数进行转义,避免SQL注入攻击)
|
||||
// 1. 针对采用 ${}写法的表名和字段进行转义和check
|
||||
String table = SqlInjectionUtil.getSqlInjectTableName(query.getTable());
|
||||
String text = SqlInjectionUtil.getSqlInjectTableName(query.getText());
|
||||
String code = SqlInjectionUtil.getSqlInjectTableName(query.getCode());
|
||||
query.setCode(table);
|
||||
query.setTable(text);
|
||||
query.setText(code);
|
||||
|
||||
// 2.表字典黑名单check
|
||||
String dictCode = table+","+text+","+code;
|
||||
if(!dictQueryBlackListHandler.isPass(dictCode)){
|
||||
log.error(dictQueryBlackListHandler.getError());
|
||||
return null;
|
||||
}
|
||||
|
||||
// 3.SQL注入check
|
||||
SqlInjectionUtil.filterContent(dictCode);
|
||||
|
||||
Page<DictModel> pageList = baseMapper.queryDictTablePageList(page, query);
|
||||
return pageList.getRecords();
|
||||
}
|
||||
|
@ -419,17 +643,8 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
|
|||
// 字典Code格式不正确
|
||||
return null;
|
||||
}
|
||||
//SQL注入校验(只限制非法串改数据库)
|
||||
//update-begin-author:taoyan date:2022-7-4 for: issues/I5BNY9 指定带过滤条件的字典table在生成代码后失效
|
||||
// 表名后也有可能带条件and语句 不能走filterContent方法
|
||||
SqlInjectionUtil.specialFilterContentForDictSql(params[0]);
|
||||
final String[] sqlInjCheck = {params[1], params[2]};
|
||||
//update-end-author:taoyan date:2022-7-4 for: issues/I5BNY9 指定带过滤条件的字典table在生成代码后失效
|
||||
//【issues/3713】字典接口存在SQL注入风险
|
||||
SqlInjectionUtil.filterContent(sqlInjCheck);
|
||||
|
||||
if (params.length == 4) {
|
||||
// SQL注入校验(查询条件SQL 特殊check,此方法仅供此处使用)
|
||||
SqlInjectionUtil.specialFilterContentForDictSql(params[3]);
|
||||
ls = this.queryTableDictItemsByCodeAndFilter(params[0], params[1], params[2], params[3]);
|
||||
} else if (params.length == 3) {
|
||||
ls = this.queryTableDictItemsByCode(params[0], params[1], params[2]);
|
||||
|
@ -454,7 +669,13 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
|
|||
|
||||
@Override
|
||||
public List<DictModel> loadDict(String dictCode, String keyword, Integer pageSize) {
|
||||
//【issues/3713】字典接口存在SQL注入风险
|
||||
// 1.表字典黑名单check
|
||||
if(!dictQueryBlackListHandler.isPass(dictCode)){
|
||||
log.error(dictQueryBlackListHandler.getError());
|
||||
return null;
|
||||
}
|
||||
|
||||
// 2.字典SQL注入风险check
|
||||
SqlInjectionUtil.specialFilterContentForDictSql(dictCode);
|
||||
|
||||
if (dictCode.contains(SymbolConstant.COMMA)) {
|
||||
|
|
Loading…
Reference in New Issue