|
|
@@ -1,7 +1,6 @@
|
|
|
package com.kxs.gateway.api.filter;
|
|
|
|
|
|
import cn.hutool.core.text.CharSequenceUtil;
|
|
|
-import cn.hutool.core.util.StrUtil;
|
|
|
import cn.hutool.crypto.symmetric.AES;
|
|
|
import com.alibaba.fastjson.JSON;
|
|
|
import com.alibaba.fastjson.JSONArray;
|
|
|
@@ -33,11 +32,9 @@ import reactor.core.publisher.Mono;
|
|
|
import java.net.URI;
|
|
|
import java.net.URLEncoder;
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
-import java.util.Arrays;
|
|
|
import java.util.List;
|
|
|
-import java.util.Objects;
|
|
|
-import java.util.concurrent.atomic.AtomicInteger;
|
|
|
-
|
|
|
+import java.util.regex.Matcher;
|
|
|
+import java.util.regex.Pattern;
|
|
|
|
|
|
|
|
|
/**
|
|
|
@@ -50,161 +47,188 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|
|
@RequiredArgsConstructor
|
|
|
public class RequestDecoderFilter extends AbstractGatewayFilterFactory<Object> {
|
|
|
|
|
|
- private final AES cryptoAes;
|
|
|
-
|
|
|
- private static final String PARAM_NAME = "value";
|
|
|
-
|
|
|
- /**
|
|
|
- * 前端所传分页名称
|
|
|
- */
|
|
|
- private static final String PAGE_NAME = "pageNum";
|
|
|
- private static final String SIZE_NAME = "pageSize";
|
|
|
-
|
|
|
- private static final List<String> FILE_TYPES = List.of("multipart/form-data");
|
|
|
-
|
|
|
- @Override
|
|
|
- public GatewayFilter apply(Object config) {
|
|
|
- return (exchange, chain) -> {
|
|
|
- ServerHttpRequest request = exchange.getRequest();
|
|
|
-
|
|
|
- MediaType contentType = request.getHeaders().getContentType();
|
|
|
-
|
|
|
- if (contentType != null && FILE_TYPES.stream().anyMatch(contentType.toString()::startsWith)) {
|
|
|
- // 这是一个文件请求
|
|
|
- return chain.filter(exchange);
|
|
|
- }
|
|
|
- // 请求方法
|
|
|
- HttpMethod method = request.getMethod();
|
|
|
- if (method == HttpMethod.GET) {
|
|
|
- // 1 修改请求参数,并获取请求参数
|
|
|
- return decryptGetRequestParam(exchange, chain);
|
|
|
- }
|
|
|
-
|
|
|
- if (method == HttpMethod.POST || method == HttpMethod.PUT) {
|
|
|
- return decryptPostBodyParam(exchange, chain);
|
|
|
- }
|
|
|
-
|
|
|
- return chain.filter(exchange);
|
|
|
-
|
|
|
- };
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 解密post-body参数
|
|
|
- *
|
|
|
- * @param exchange exchange
|
|
|
- * @param chain chain
|
|
|
- * @return mono<void>
|
|
|
- */
|
|
|
- private Mono<Void> decryptPostBodyParam(ServerWebExchange exchange, GatewayFilterChain chain) {
|
|
|
- //获取请求体,修改请求体
|
|
|
- ServerRequest serverRequest = ServerRequest.create(exchange,
|
|
|
- HandlerStrategies.withDefaults().messageReaders());
|
|
|
-
|
|
|
- //请求长度
|
|
|
- AtomicInteger setContentLength = new AtomicInteger();
|
|
|
- //获取请求头
|
|
|
- MediaType contentType = exchange.getRequest().getHeaders().getContentType();
|
|
|
- Flux<DataBuffer> modifiedBody = serverRequest.bodyToFlux(String.class).flatMap(body -> {
|
|
|
- // 解密请求体
|
|
|
- try {
|
|
|
+ private final AES cryptoAes;
|
|
|
+
|
|
|
+ private static final String PARAM_NAME = "value";
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 前端所传分页名称
|
|
|
+ */
|
|
|
+ private static final String PAGE_NAME = "pageNum";
|
|
|
+ private static final String SIZE_NAME = "pageSize";
|
|
|
+
|
|
|
+ private static final List<String> FILE_TYPES = List.of("multipart/form-data");
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public GatewayFilter apply(Object config) {
|
|
|
+ return (exchange, chain) -> {
|
|
|
+ ServerHttpRequest request = exchange.getRequest();
|
|
|
+
|
|
|
+ MediaType contentType = request.getHeaders().getContentType();
|
|
|
+
|
|
|
+ if (contentType != null && FILE_TYPES.stream().anyMatch(contentType.toString()::startsWith)) {
|
|
|
+ // 这是一个文件请求
|
|
|
+ return chain.filter(exchange);
|
|
|
+ }
|
|
|
+ // 请求方法
|
|
|
+ HttpMethod method = request.getMethod();
|
|
|
+ if (method == HttpMethod.GET) {
|
|
|
+ // 1 修改请求参数,并获取请求参数
|
|
|
+ return decryptGetRequestParam(exchange, chain);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (method == HttpMethod.POST || method == HttpMethod.PUT ) {
|
|
|
+ return decryptPostBodyParam(exchange, chain);
|
|
|
+ }
|
|
|
+ if (method == HttpMethod.DELETE) {
|
|
|
+ // 1 修改请求参数,并获取请求参数
|
|
|
+ return decryptDeleteRequestParam(exchange, chain);
|
|
|
+ }
|
|
|
+
|
|
|
+ return chain.filter(exchange);
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private Mono<Void> decryptDeleteRequestParam(ServerWebExchange exchange, GatewayFilterChain chain) {
|
|
|
+
|
|
|
+ ServerHttpRequest request = exchange.getRequest();
|
|
|
+ URI uri = exchange.getRequest().getURI();
|
|
|
+ String path = uri.getPath();
|
|
|
+ try{
|
|
|
+ String[] pathSegments = path.split("/");
|
|
|
+ String param = pathSegments[pathSegments.length - 1];
|
|
|
+
|
|
|
+ String decryptStr = cryptoAes.decryptStr(param);
|
|
|
+
|
|
|
+ Pattern pattern = Pattern.compile("(.+/)[^/]+$");
|
|
|
+ Matcher matcher = pattern.matcher(path);
|
|
|
+
|
|
|
+ if (matcher.find()) {
|
|
|
+ String lastSegment = matcher.group(1); // 包括最后一个/
|
|
|
+ path = lastSegment + decryptStr;
|
|
|
+ request = exchange.getRequest().mutate().uri(URI.create(path)).build();
|
|
|
+ }
|
|
|
+ }catch (Exception e) {
|
|
|
+ log.error("解密异常,请求地址:{}", path);
|
|
|
+ return Mono.error(new AesDecodeException(ErrorTypeEnum.DECRYPT_ERROR.getDescription()));
|
|
|
+ }
|
|
|
+
|
|
|
+ return chain.filter(exchange.mutate().request(request.mutate().build()).build());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解密post-body参数
|
|
|
+ *
|
|
|
+ * @param exchange exchange
|
|
|
+ * @param chain chain
|
|
|
+ * @return mono<void>
|
|
|
+ */
|
|
|
+ private Mono<Void> decryptPostBodyParam(ServerWebExchange exchange, GatewayFilterChain chain) {
|
|
|
+ //获取请求体,修改请求体
|
|
|
+ ServerRequest serverRequest = ServerRequest.create(exchange,
|
|
|
+ HandlerStrategies.withDefaults().messageReaders());
|
|
|
+
|
|
|
+ //获取请求头
|
|
|
+ MediaType contentType = exchange.getRequest().getHeaders().getContentType();
|
|
|
+ Flux<DataBuffer> modifiedBody = serverRequest.bodyToFlux(String.class).flatMap(body -> {
|
|
|
+ // 解密请求体
|
|
|
+ try {
|
|
|
// log.info("待解密请求参数:{}", body);
|
|
|
- String decryptStr = cryptoAes.decryptStr(body);
|
|
|
+ String decryptStr = cryptoAes.decryptStr(body);
|
|
|
// log.info("解密后参数:{}", decryptStr);
|
|
|
|
|
|
- DataBufferFactory dataBufferFactory = exchange.getResponse().bufferFactory();
|
|
|
- DataBuffer bodyDataBuffer = dataBufferFactory.wrap(decryptStr.getBytes());
|
|
|
- //获取参数长度
|
|
|
-// setContentLength.set(encrypt.getBytes().length);
|
|
|
- //添加到请求体
|
|
|
- return Flux.just(bodyDataBuffer);
|
|
|
- } catch (Exception e) {
|
|
|
- log.error(ErrorTypeEnum.DECRYPT_ERROR.getDescription(), e);
|
|
|
- return Flux.error(new AesDecodeException(ErrorTypeEnum.DECRYPT_ERROR.getDescription()));
|
|
|
- }
|
|
|
- });
|
|
|
- ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
|
|
|
- exchange.getRequest()) {
|
|
|
- @NotNull
|
|
|
- @Override
|
|
|
- public HttpHeaders getHeaders() {
|
|
|
- //重新设置请求头
|
|
|
- HttpHeaders httpHeaders = new HttpHeaders();
|
|
|
- httpHeaders.putAll(super.getHeaders());
|
|
|
- httpHeaders.remove(HttpHeaders.CONTENT_TYPE);
|
|
|
- httpHeaders.remove(HttpHeaders.CONTENT_LENGTH);
|
|
|
- assert contentType != null;
|
|
|
- httpHeaders.set(HttpHeaders.CONTENT_TYPE, contentType.toString());
|
|
|
-
|
|
|
- return httpHeaders;
|
|
|
- }
|
|
|
-
|
|
|
- @NotNull
|
|
|
- @Override
|
|
|
- public Flux<DataBuffer> getBody() {
|
|
|
- return modifiedBody;
|
|
|
- }
|
|
|
- };
|
|
|
- return chain.filter(exchange.mutate().request(mutatedRequest).build());
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * 解密GET请求参数
|
|
|
- *
|
|
|
- * @param exchange exchange
|
|
|
- * @param chain chain
|
|
|
- * @return mono<void>
|
|
|
- */
|
|
|
- private Mono<Void> decryptGetRequestParam(ServerWebExchange exchange, GatewayFilterChain chain) {
|
|
|
-
|
|
|
- try {
|
|
|
- MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
|
|
|
- String decryptedParam = queryParams.getFirst(PARAM_NAME);
|
|
|
- if(CharSequenceUtil.isEmpty(decryptedParam)){
|
|
|
- return chain.filter(exchange);
|
|
|
- }
|
|
|
+ DataBufferFactory dataBufferFactory = exchange.getResponse().bufferFactory();
|
|
|
+ DataBuffer bodyDataBuffer = dataBufferFactory.wrap(decryptStr.getBytes());
|
|
|
+ //添加到请求体
|
|
|
+ return Flux.just(bodyDataBuffer);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error(ErrorTypeEnum.DECRYPT_ERROR.getDescription(), e);
|
|
|
+ return Flux.error(new AesDecodeException(ErrorTypeEnum.DECRYPT_ERROR.getDescription()));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
|
|
|
+ exchange.getRequest()) {
|
|
|
+ @NotNull
|
|
|
+ @Override
|
|
|
+ public HttpHeaders getHeaders() {
|
|
|
+ //重新设置请求头
|
|
|
+ HttpHeaders httpHeaders = new HttpHeaders();
|
|
|
+ httpHeaders.putAll(super.getHeaders());
|
|
|
+ httpHeaders.remove(HttpHeaders.CONTENT_TYPE);
|
|
|
+ httpHeaders.remove(HttpHeaders.CONTENT_LENGTH);
|
|
|
+ assert contentType != null;
|
|
|
+ httpHeaders.set(HttpHeaders.CONTENT_TYPE, contentType.toString());
|
|
|
+
|
|
|
+ return httpHeaders;
|
|
|
+ }
|
|
|
+
|
|
|
+ @NotNull
|
|
|
+ @Override
|
|
|
+ public Flux<DataBuffer> getBody() {
|
|
|
+ return modifiedBody;
|
|
|
+ }
|
|
|
+ };
|
|
|
+ return chain.filter(exchange.mutate().request(mutatedRequest).build());
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解密GET请求参数
|
|
|
+ *
|
|
|
+ * @param exchange exchange
|
|
|
+ * @param chain chain
|
|
|
+ * @return mono<void>
|
|
|
+ */
|
|
|
+ private Mono<Void> decryptGetRequestParam(ServerWebExchange exchange, GatewayFilterChain chain) {
|
|
|
+
|
|
|
+ try {
|
|
|
+ MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
|
|
|
+ String decryptedParam = queryParams.getFirst(PARAM_NAME);
|
|
|
+ if (CharSequenceUtil.isEmpty(decryptedParam)) {
|
|
|
+ return chain.filter(exchange);
|
|
|
+ }
|
|
|
// log.info("GET:{},请求待解密数据 :{}", exchange.getRequest().getURI(),decryptedParam);
|
|
|
- String decryptStr = cryptoAes.decryptStr(decryptedParam);
|
|
|
-// log.info("GET解密后数据 :{}", decryptStr);
|
|
|
-
|
|
|
- JSONObject decryptJson = JSON.parseObject(decryptStr);
|
|
|
- //构建新的请求参数webflux
|
|
|
- MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>(decryptJson.size());
|
|
|
- decryptJson.forEach((key, value) -> {
|
|
|
- //转换分页参数,前后端定义不一致的问题
|
|
|
- if(PAGE_NAME.equals(key)){
|
|
|
- key = "current";
|
|
|
- }
|
|
|
- if(SIZE_NAME.equals(key)){
|
|
|
- key = "size";
|
|
|
- }
|
|
|
- if(value instanceof JSONArray){
|
|
|
- JSONArray values = JSON.parseArray(value.toString());
|
|
|
- String finalKey = key;
|
|
|
- values.forEach(v -> parameters.add(finalKey, URLEncoder.encode(String.valueOf(v), StandardCharsets.UTF_8)));
|
|
|
- }else{
|
|
|
- parameters.add(key, URLEncoder.encode(String.valueOf(value), StandardCharsets.UTF_8));
|
|
|
- }
|
|
|
- });
|
|
|
+ String decryptStr = cryptoAes.decryptStr(decryptedParam);
|
|
|
+ log.info("GET解密后数据 :{}", decryptStr);
|
|
|
+
|
|
|
+ JSONObject decryptJson = JSON.parseObject(decryptStr);
|
|
|
+ //构建新的请求参数webflux
|
|
|
+ MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>(decryptJson.size());
|
|
|
+ decryptJson.forEach((key, value) -> {
|
|
|
+ //转换分页参数,前后端定义不一致的问题
|
|
|
+ if (PAGE_NAME.equals(key)) {
|
|
|
+ key = "current";
|
|
|
+ }
|
|
|
+ if (SIZE_NAME.equals(key)) {
|
|
|
+ key = "size";
|
|
|
+ }
|
|
|
+ if (value instanceof JSONArray) {
|
|
|
+ JSONArray values = JSON.parseArray(value.toString());
|
|
|
+ String finalKey = key;
|
|
|
+ values.forEach(v -> parameters.add(finalKey, URLEncoder.encode(String.valueOf(v), StandardCharsets.UTF_8)));
|
|
|
+ } else {
|
|
|
+ parameters.add(key, URLEncoder.encode(String.valueOf(value), StandardCharsets.UTF_8));
|
|
|
+ }
|
|
|
+ });
|
|
|
// log.info("GET解密后数据 :{}", parameters);
|
|
|
- // 构建修改后的URI
|
|
|
- URI modifiedUri = UriComponentsBuilder.fromUri(exchange.getRequest().getURI())
|
|
|
- .replaceQueryParams(parameters)
|
|
|
- .build(true)
|
|
|
- .toUri();
|
|
|
- // 修改请求,设置新的URI
|
|
|
- ServerHttpRequest modifiedRequest = exchange.getRequest().mutate()
|
|
|
- .uri(modifiedUri)
|
|
|
- .build();
|
|
|
- // 用修改后的请求继续处理请求链
|
|
|
- return chain.filter(exchange.mutate().request(modifiedRequest).build());
|
|
|
- } catch (Exception e) {
|
|
|
- log.error(ErrorTypeEnum.DECRYPT_ERROR.getDescription(), e);
|
|
|
- return Mono.error(new AesDecodeException(ErrorTypeEnum.DECRYPT_ERROR.getDescription()));
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
+ // 构建修改后的URI
|
|
|
+ URI modifiedUri = UriComponentsBuilder.fromUri(exchange.getRequest().getURI())
|
|
|
+ .replaceQueryParams(parameters)
|
|
|
+ .build(true)
|
|
|
+ .toUri();
|
|
|
+ // 修改请求,设置新的URI
|
|
|
+ ServerHttpRequest modifiedRequest = exchange.getRequest().mutate()
|
|
|
+ .uri(modifiedUri)
|
|
|
+ .build();
|
|
|
+ // 用修改后的请求继续处理请求链
|
|
|
+ return chain.filter(exchange.mutate().request(modifiedRequest).build());
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error(ErrorTypeEnum.DECRYPT_ERROR.getDescription(), e);
|
|
|
+ return Mono.error(new AesDecodeException(ErrorTypeEnum.DECRYPT_ERROR.getDescription()));
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
}
|