对齐 boot 与 cloud 的代码

This commit is contained in:
YunaiV
2023-07-27 13:01:17 +08:00
parent 1475e9a507
commit 0feb865ef0
53 changed files with 413 additions and 237 deletions

View File

@@ -4,6 +4,7 @@ import cn.hutool.core.date.LocalDateTimeUtil;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;
/**
* 时间工具类,用于 {@link java.time.LocalDateTime}
@@ -50,7 +51,7 @@ public class LocalDateTimeUtils {
* 判断当前时间是否在该时间范围内
*
* @param startTime 开始时间
* @param endTime 结束时间
* @param endTime 结束时间
* @return 是否
*/
public static boolean isBetween(LocalDateTime startTime, LocalDateTime endTime) {
@@ -60,4 +61,24 @@ public class LocalDateTimeUtils {
return LocalDateTimeUtil.isIn(LocalDateTime.now(), startTime, endTime);
}
/**
* 检查时间重叠 不包含日期
*
* @param startTime1 需要校验的开始时间
* @param endTime1 需要校验的结束时间
* @param startTime2 校验所需的开始时间
* @param endTime2 校验所需的结束时间
* @return 是否重叠
*/
// TODO @puhui999LocalDateTimeUtil.isOverlap() 是不是可以满足呀?
public static boolean checkTimeOverlap(LocalTime startTime1, LocalTime endTime1, LocalTime startTime2, LocalTime endTime2) {
// 判断时间是否重叠
// 开始时间在已配置时段的结束时间之前 且 结束时间在已配置时段的开始时间之后 []
return startTime1.isBefore(endTime2) && endTime1.isAfter(startTime2)
// 开始时间在已配置时段的开始时间之前 且 结束时间在已配置时段的开始时间之后 (] 或 ()
|| startTime1.isBefore(startTime2) && endTime1.isAfter(startTime2)
// 开始时间在已配置时段的结束时间之前 且 结束时间在已配值时段的结束时间之后 [) 或 ()
|| startTime1.isBefore(endTime2) && endTime1.isAfter(endTime2);
}
}

View File

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.common.util.spring;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
@@ -24,7 +25,13 @@ import java.util.Map;
*/
public class SpringExpressionUtils {
/**
* spel表达式解析器
*/
private static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();
/**
* 参数名发现器
*/
private static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
private SpringExpressionUtils() {
@@ -33,7 +40,7 @@ public class SpringExpressionUtils {
/**
* 从切面中,单个解析 EL 表达式的结果
*
* @param joinPoint 切面点
* @param joinPoint 切面点
* @param expressionString EL 表达式数组
* @return 执行界面
*/
@@ -45,7 +52,7 @@ public class SpringExpressionUtils {
/**
* 从切面中,批量解析 EL 表达式的结果
*
* @param joinPoint 切面点
* @param joinPoint 切面点
* @param expressionStrings EL 表达式数组
* @return 结果key 为表达式value 为对应值
*/
@@ -79,4 +86,48 @@ public class SpringExpressionUtils {
});
return result;
}
/**
* JoinPoint 切面 批量解析 EL 表达式,转换 jspl参数
*
* @param joinPoint 切面点
* @param info 返回值
* @param expressionStrings EL 表达式数组
* @return Map<String, Object> 结果
* @author 陈賝
* @since 2023/6/18 11:20
*/
// TODO @chenchen: 这个方法,和 parseExpressions 比较接近,是不是可以合并下;
public static Map<String, Object> parseExpression(JoinPoint joinPoint, Object info, List<String> expressionStrings) {
// 如果为空,则不进行解析
if (CollUtil.isEmpty(expressionStrings)) {
return MapUtil.newHashMap();
}
// 第一步,构建解析的上下文 EvaluationContext
// 通过 joinPoint 获取被注解方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
// 使用 spring 的 ParameterNameDiscoverer 获取方法形参名数组
String[] parameterNames = PARAMETER_NAME_DISCOVERER.getParameterNames(method);
// Spring 的表达式上下文对象
EvaluationContext context = new StandardEvaluationContext();
if (ArrayUtil.isNotEmpty(parameterNames)) {
//获取方法参数值
Object[] args = joinPoint.getArgs();
for (int i = 0; i < args.length; i++) {
// 替换 SP EL 里的变量值为实际值, 比如 #user --> user对象
context.setVariable(parameterNames[i], args[i]);
}
context.setVariable("info", info);
}
// 第二步,逐个参数解析
Map<String, Object> result = MapUtil.newHashMap(expressionStrings.size(), true);
expressionStrings.forEach(key -> {
Object value = EXPRESSION_PARSER.parseExpression(key).getValue(context);
result.put(key, value);
});
return result;
}
}

View File

@@ -38,7 +38,7 @@ public class TenantContextHolder {
Long tenantId = getTenantId();
if (tenantId == null) {
throw new NullPointerException("TenantContextHolder 不存在租户编号!可参考文档:"
+ DocumentEnum.TENANT.getUrl());
+ DocumentEnum.TENANT.getUrl());
}
return tenantId;
}

View File

@@ -63,6 +63,10 @@
<artifactId>dynamic-datasource-spring-boot-starter</artifactId> <!-- 多数据源 -->
</dependency>
<dependency>
<groupId>com.github.yulichang</groupId>
<artifactId>mybatis-plus-join-boot-starter</artifactId> <!-- MyBatis 联表查询 -->
</dependency>
</dependencies>
</project>

View File

@@ -60,7 +60,7 @@ public class YudaoWebSecurityConfigurerAdapter {
/**
* 自定义的权限映射 Bean 们
*
* @see #configure(HttpSecurity)
* @see #filterChain(HttpSecurity)
*/
@Resource
private List<AuthorizeRequestsCustomizer> authorizeRequestsCustomizers;
@@ -95,7 +95,7 @@ public class YudaoWebSecurityConfigurerAdapter {
* authenticated | 用户登录后可访问
*/
@Bean
protected SecurityFilterChain configure(HttpSecurity httpSecurity) throws Exception {
protected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
// 登出
httpSecurity
// 开启跨域
@@ -116,16 +116,16 @@ public class YudaoWebSecurityConfigurerAdapter {
httpSecurity
// ①:全局共享规则
.authorizeRequests()
// 静态资源,可匿名访问
// 1.1 静态资源,可匿名访问
.antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll()
// 设置 @PermitAll 无需认证
// 1.2 设置 @PermitAll 无需认证
.antMatchers(HttpMethod.GET, permitAllUrls.get(HttpMethod.GET).toArray(new String[0])).permitAll()
.antMatchers(HttpMethod.POST, permitAllUrls.get(HttpMethod.POST).toArray(new String[0])).permitAll()
.antMatchers(HttpMethod.PUT, permitAllUrls.get(HttpMethod.PUT).toArray(new String[0])).permitAll()
.antMatchers(HttpMethod.DELETE, permitAllUrls.get(HttpMethod.DELETE).toArray(new String[0])).permitAll()
// 基于 yudao.security.permit-all-urls 无需认证
// 1.3 基于 yudao.security.permit-all-urls 无需认证
.antMatchers(securityProperties.getPermitAllUrls().toArray(new String[0])).permitAll()
// 设置 App API 无需认证
// 1.4 设置 App API 无需认证
.antMatchers(buildAppApi("/**")).permitAll()
// ②:每个项目的自定义规则
.and().authorizeRequests(registry -> // 下面,循环设置自定义规则
@@ -135,7 +135,7 @@ public class YudaoWebSecurityConfigurerAdapter {
.anyRequest().authenticated()
;
// 添加 JWT Filter
// 添加 Token Filter
httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
return httpSecurity.build();
}

View File

@@ -8,7 +8,6 @@ import cn.iocoder.yudao.framework.test.config.SqlInitializationTestConfiguration
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
import org.redisson.spring.starter.RedissonAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
@@ -41,7 +40,7 @@ public class BaseDbAndRedisUnitTest {
// Redis 配置类
RedisTestConfiguration.class, // Redis 测试配置类,用于启动 RedisServer
RedisAutoConfiguration.class, // Spring Redis 自动配置类
// RedisAutoConfiguration.class, // Spring Redis 自动配置类
YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类
RedissonAutoConfiguration.class, // Redisson 自动高配置类
})

View File

@@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration;
import cn.iocoder.yudao.framework.test.config.SqlInitializationTestConfiguration;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
import com.github.yulichang.autoconfigure.MybatisPlusJoinAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
@@ -34,6 +35,7 @@ public class BaseDbUnitTest {
// MyBatis 配置类
YudaoMybatisAutoConfiguration.class, // 自己的 MyBatis 配置类
MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类
MybatisPlusJoinAutoConfiguration.class, // MyBatis 的Join配置类
})
public static class Application {
}

View File

@@ -12,15 +12,13 @@ import cn.iocoder.yudao.module.infra.api.logger.ApiAccessLogApi;
import cn.iocoder.yudao.module.infra.api.logger.ApiErrorLogApi;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import javax.servlet.Filter;
@AutoConfiguration
@AutoConfigureAfter(YudaoWebAutoConfiguration.class)
@AutoConfiguration(after = YudaoWebAutoConfiguration.class)
public class YudaoApiLogAutoConfiguration {
@Bean

View File

@@ -3,7 +3,6 @@ package cn.iocoder.yudao.framework.apilog.core.filter;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.iocoder.yudao.framework.apilog.core.service.ApiAccessLog;
import cn.iocoder.yudao.framework.apilog.core.service.ApiAccessLogFrameworkService;
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
@@ -50,8 +49,8 @@ public class ApiAccessLogFilter extends ApiRequestFilter {
// 获得开始时间
LocalDateTime beginTime = LocalDateTime.now();
// 提前获得参数,避免 XssFilter 过滤处理
Map<String, String> queryString = ServletUtil.getParamMap(request);
String requestBody = ServletUtils.isJsonRequest(request) ? ServletUtil.getBody(request) : null;
Map<String, String> queryString = ServletUtils.getParamMap(request);
String requestBody = ServletUtils.isJsonRequest(request) ? ServletUtils.getBody(request) : null;
try {
// 继续过滤器
@@ -101,7 +100,7 @@ public class ApiAccessLogFilter extends ApiRequestFilter {
accessLog.setRequestParams(toJsonString(requestParams));
accessLog.setRequestMethod(request.getMethod());
accessLog.setUserAgent(ServletUtils.getUserAgent(request));
accessLog.setUserIp(ServletUtil.getClientIP(request));
accessLog.setUserIp(ServletUtils.getClientIP(request));
// 持续时间
accessLog.setBeginTime(beginTime);
accessLog.setEndTime(LocalDateTime.now());

View File

@@ -1 +1,4 @@
/**
* Web 框架全局异常、API 日志等
*/
package cn.iocoder.yudao.framework;

View File

@@ -2,28 +2,22 @@ package cn.iocoder.yudao.framework.web.config;
import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLogFrameworkService;
import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
import cn.iocoder.yudao.framework.web.core.clean.JsoupXssCleaner;
import cn.iocoder.yudao.framework.web.core.clean.XssCleaner;
import cn.iocoder.yudao.framework.web.core.filter.CacheRequestBodyFilter;
import cn.iocoder.yudao.framework.web.core.filter.DemoFilter;
import cn.iocoder.yudao.framework.web.core.filter.XssFilter;
import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
import cn.iocoder.yudao.framework.web.core.handler.GlobalResponseBodyHandler;
import cn.iocoder.yudao.framework.web.core.json.XssStringJsonDeserializer;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@@ -34,7 +28,7 @@ import javax.annotation.Resource;
import javax.servlet.Filter;
@AutoConfiguration
@EnableConfigurationProperties({WebProperties.class, XssProperties.class})
@EnableConfigurationProperties(WebProperties.class)
public class YudaoWebAutoConfiguration implements WebMvcConfigurer {
@Resource
@@ -107,15 +101,6 @@ public class YudaoWebAutoConfiguration implements WebMvcConfigurer {
return createFilterBean(new CacheRequestBodyFilter(), WebFilterOrderEnum.REQUEST_BODY_CACHE_FILTER);
}
/**
* 创建 XssFilter Bean解决 Xss 安全问题
*/
@Bean
@ConditionalOnBean(XssCleaner.class)
public FilterRegistrationBean<XssFilter> xssFilter(XssProperties properties, PathMatcher pathMatcher, XssCleaner xssCleaner) {
return createFilterBean(new XssFilter(properties, pathMatcher, xssCleaner), WebFilterOrderEnum.XSS_FILTER);
}
/**
* 创建 DemoFilter Bean演示模式
*/
@@ -125,37 +110,19 @@ public class YudaoWebAutoConfiguration implements WebMvcConfigurer {
return createFilterBean(new DemoFilter(), WebFilterOrderEnum.DEMO_FILTER);
}
/**
* Xss 清理者
*
* @return XssCleaner
*/
@ConditionalOnMissingBean(XssCleaner.class)
@Bean
public XssCleaner xssCleaner() {
return new JsoupXssCleaner();
}
/**
* 注册 Jackson 的序列化器,用于处理 json 类型参数的 xss 过滤
*
* @return Jackson2ObjectMapperBuilderCustomizer
*/
@Bean
@ConditionalOnMissingBean(name = "xssJacksonCustomizer")
@ConditionalOnBean(ObjectMapper.class)
@ConditionalOnProperty(value = "yudao.xss.enable", havingValue = "true")
public Jackson2ObjectMapperBuilderCustomizer xssJacksonCustomizer(XssCleaner xssCleaner) {
// 在反序列化时进行 xss 过滤,可以替换使用 XssStringJsonSerializer在序列化时进行处理
return builder -> builder.deserializerByType(String.class, new XssStringJsonDeserializer(xssCleaner));
}
private static <T extends Filter> FilterRegistrationBean<T> createFilterBean(T filter, Integer order) {
public static <T extends Filter> FilterRegistrationBean<T> createFilterBean(T filter, Integer order) {
FilterRegistrationBean<T> bean = new FilterRegistrationBean<>(filter);
bean.setOrder(order);
return bean;
}
/**
* 创建 RestTemplate 实例
*
* @param restTemplateBuilder {@link RestTemplateAutoConfiguration#restTemplateBuilder}
*/
@Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
return restTemplateBuilder.build();
}
}

View File

@@ -1,4 +1,4 @@
package cn.iocoder.yudao.framework.web.config;
package cn.iocoder.yudao.framework.xss.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

View File

@@ -0,0 +1,60 @@
package cn.iocoder.yudao.framework.xss.config;
import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
import cn.iocoder.yudao.framework.xss.core.clean.JsoupXssCleaner;
import cn.iocoder.yudao.framework.xss.core.clean.XssCleaner;
import cn.iocoder.yudao.framework.xss.core.filter.XssFilter;
import cn.iocoder.yudao.framework.xss.core.json.XssStringJsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.util.PathMatcher;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import static cn.iocoder.yudao.framework.web.config.YudaoWebAutoConfiguration.createFilterBean;
@AutoConfiguration
@EnableConfigurationProperties(XssProperties.class)
public class YudaoXssAutoConfiguration implements WebMvcConfigurer {
/**
* Xss 清理者
*
* @return XssCleaner
*/
@Bean
@ConditionalOnMissingBean(XssCleaner.class)
public XssCleaner xssCleaner() {
return new JsoupXssCleaner();
}
/**
* 注册 Jackson 的序列化器,用于处理 json 类型参数的 xss 过滤
*
* @return Jackson2ObjectMapperBuilderCustomizer
*/
@Bean
@ConditionalOnMissingBean(name = "xssJacksonCustomizer")
@ConditionalOnBean(ObjectMapper.class)
@ConditionalOnProperty(value = "yudao.xss.enable", havingValue = "true")
public Jackson2ObjectMapperBuilderCustomizer xssJacksonCustomizer(XssCleaner xssCleaner) {
// 在反序列化时进行 xss 过滤,可以替换使用 XssStringJsonSerializer在序列化时进行处理
return builder -> builder.deserializerByType(String.class, new XssStringJsonDeserializer(xssCleaner));
}
/**
* 创建 XssFilter Bean解决 Xss 安全问题
*/
@Bean
@ConditionalOnBean(XssCleaner.class)
public FilterRegistrationBean<XssFilter> xssFilter(XssProperties properties, PathMatcher pathMatcher, XssCleaner xssCleaner) {
return createFilterBean(new XssFilter(properties, pathMatcher, xssCleaner), WebFilterOrderEnum.XSS_FILTER);
}
}

View File

@@ -1,11 +1,11 @@
package cn.iocoder.yudao.framework.web.core.clean;
package cn.iocoder.yudao.framework.xss.core.clean;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.safety.Safelist;
/**
* jsonp 过滤字符串
* 基于 JSONP 实现 XSS 过滤字符串
*/
public class JsoupXssCleaner implements XssCleaner {
@@ -24,21 +24,6 @@ public class JsoupXssCleaner implements XssCleaner {
this.baseUri = "";
}
public JsoupXssCleaner(Safelist safelist) {
this.safelist = safelist;
this.baseUri = "";
}
public JsoupXssCleaner(String baseUri) {
this.safelist = buildSafelist();
this.baseUri = baseUri;
}
public JsoupXssCleaner(Safelist safelist, String baseUri) {
this.safelist = safelist;
this.baseUri = baseUri;
}
/**
* 构建一个 Xss 清理的 Safelist 规则
* 基于 Safelist#relaxed() 的基础上:
@@ -67,7 +52,6 @@ public class JsoupXssCleaner implements XssCleaner {
// 虽然可以重写 WhiteList#isSafeAttribute 来处理但是有隐患所以暂时不支持相对路径
// WHITELIST.removeProtocols("a", "href", "ftp", "http", "https", "mailto");
// WHITELIST.removeProtocols("img", "src", "http", "https");
return relaxedSafelist;
}

View File

@@ -1,4 +1,4 @@
package cn.iocoder.yudao.framework.web.core.clean;
package cn.iocoder.yudao.framework.xss.core.clean;
/**
* html 文本中的有 Xss 风险的数据进行清理
@@ -12,4 +12,5 @@ public interface XssCleaner {
* @return 清理后的 html
*/
String clean(String html);
}

View File

@@ -1,7 +1,7 @@
package cn.iocoder.yudao.framework.web.core.filter;
package cn.iocoder.yudao.framework.xss.core.filter;
import cn.iocoder.yudao.framework.web.config.XssProperties;
import cn.iocoder.yudao.framework.web.core.clean.XssCleaner;
import cn.iocoder.yudao.framework.xss.config.XssProperties;
import cn.iocoder.yudao.framework.xss.core.clean.XssCleaner;
import lombok.AllArgsConstructor;
import org.springframework.util.PathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;
@@ -14,8 +14,6 @@ import java.io.IOException;
/**
* Xss 过滤器
* <p>
* Xss 不了解的胖友可以看看 http://www.iocoder.cn/Fight/The-new-girl-asked-me-why-AJAX-requests-are-not-secure-I-did-not-answer/
*
* @author 芋道源码
*/

View File

@@ -1,6 +1,6 @@
package cn.iocoder.yudao.framework.web.core.filter;
package cn.iocoder.yudao.framework.xss.core.filter;
import cn.iocoder.yudao.framework.web.core.clean.XssCleaner;
import cn.iocoder.yudao.framework.xss.core.clean.XssCleaner;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
@@ -13,6 +13,7 @@ import java.util.Map;
* @author 芋道源码
*/
public class XssRequestWrapper extends HttpServletRequestWrapper {
private final XssCleaner xssCleaner;
public XssRequestWrapper(HttpServletRequest request, XssCleaner xssCleaner) {

View File

@@ -1,6 +1,6 @@
package cn.iocoder.yudao.framework.web.core.json;
package cn.iocoder.yudao.framework.xss.core.json;
import cn.iocoder.yudao.framework.web.core.clean.XssCleaner;
import cn.iocoder.yudao.framework.xss.core.clean.XssCleaner;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;

View File

@@ -0,0 +1,6 @@
/**
* 针对 XSS 的基础封装
*
* XSS 说明https://tech.meituan.com/2018/09/27/fe-security.html
*/
package cn.iocoder.yudao.framework.xss;