首页 前端知识 Gateway 解决body流重复获取,对application/json,multipart/form-data,x-www-form-urlencoded 参数加解密和 增删参数

Gateway 解决body流重复获取,对application/json,multipart/form-data,x-www-form-urlencoded 参数加解密和 增删参数

2024-04-29 11:04:53 前端知识 前端哥 134 592 我要收藏
1. CacheRequestFilter  全局过滤器 解决body流重复获取 
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Component
public class CacheRequestFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
if (request.getHeaders().getContentType() == null) {
return chain.filter(exchange);
}
HttpMethod method = request.getMethod();
if (method == null || method.matches("GET") || method.matches("DELETE")) {
return chain.filter(exchange);
}
//当body中没有缓存时,只会执行这一个拦截器, 原因是fileMap中的代码没有执行,所以需要在为空时构建一个空的缓存
DefaultDataBufferFactory defaultDataBufferFactory = new DefaultDataBufferFactory();
DefaultDataBuffer defaultDataBuffer = defaultDataBufferFactory.allocateBuffer(0);
//构建新数据流, 当body为空时,构建空流
Flux<DataBuffer> bodyDataBuffer = exchange.getRequest().getBody().defaultIfEmpty(defaultDataBuffer);
return DataBufferUtils.join(bodyDataBuffer)
.flatMap(dataBuffer -> {
DataBufferUtils.retain(dataBuffer);
Flux<DataBuffer> cachedFlux = Flux
.defer(() -> Flux.just(dataBuffer.slice(0, dataBuffer.readableByteCount())));
ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(exchange.getRequest()) {
@Override
public Flux<DataBuffer> getBody() {
return cachedFlux;
}
};
//exchange.getAttributes().put(CACHE_REQUEST_BODY_OBJECT_KEY, cachedFlux);
return chain.filter(exchange.mutate().request(mutatedRequest).build());
});
}
@Override
public int getOrder() {
return 0;
}
}
复制

2.加解密的类型包括json/ form-data/x-www-form-urlencoded   
3. 对body 里的参数 进行加解密 和 增删参数  进行向下传递  (这里采用AES加解密)
package com.suntae.gateway.filter;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.suntae.common.domain.ResultException;
import com.suntae.gateway.utils.AESUtils;
import io.netty.buffer.ByteBufAllocator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.NettyDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.net.URLDecoder;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Map;
@Slf4j
@Component
public class DeCodeGlobalFilter implements GlobalFilter, Ordered {
private final static String sk = "aes密钥";
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
HttpMethod method = request.getMethod();
long contentLength = request.getHeaders().getContentLength();
if (contentLength > 0) {
//只针对post请求解码
if (HttpMethod.POST.equals(method)) {
return handlePostMethod(exchange, request, chain);
}
}
return chain.filter(exchange);
}
private Mono<Void> handlePostMethod(ServerWebExchange exchange, ServerHttpRequest request, GatewayFilterChain chain) {
MediaType contentType = request.getHeaders().getContentType();
if (contentType == null) {
return Mono.error(new ResultException("未识别的请求体类型"));
}
StringBuffer paramBuffer = new StringBuffer();
Flux<DataBuffer> body = exchange.getRequest().getBody();
body.subscribe(buffer -> {
//解析body 数据
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
//在这里解密 并 重新塞进去
paramBuffer.append(charBuffer);
});
//获取到最后的body 中的数据
String param = paramBuffer.toString();
JSONObject JsonData = null;
if (MediaType.APPLICATION_JSON.isCompatibleWith(contentType)) {
JsonData = JSONObject.parseObject(param);
}
if (MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(contentType)) {
JsonData = handleFormURLEncoded(param);
}
if (MediaType.MULTIPART_FORM_DATA.isCompatibleWith(contentType)) {
JsonData = JSON.parseObject(handleFormData(param, contentType.toString()));
}
if (JsonData == null) {
return Mono.error(new ResultException("不支持的请求体类型"));
}
for (String str : JsonData.keySet()) {
log.info("参数:{}", str);
log.info("{}解密前:{}", str, JsonData.get(str));
//解密前的值
String enCode = JsonData.getString(str);
String deCode;
try {
deCode = AESUtils.decrypt(URLDecoder.decode(enCode, "UTF-8"), sk);
} catch (Exception e) {
throw new ResultException("解密失败");
}
// 解密后的
log.info("{}解密后:{}", str, deCode);
param = param.replace(enCode, deCode);
}
String bodyStr = param;
DataBuffer bodyDataBuffer = stringBuffer(bodyStr);
Flux<DataBuffer> bodyFlux = Flux.just(bodyDataBuffer);
ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
exchange.getRequest()) {
@Override
public HttpHeaders getHeaders() {
HttpHeaders httpHeaders = new HttpHeaders();
int length = bodyStr.getBytes().length;
httpHeaders.putAll(super.getHeaders());
httpHeaders.remove(HttpHeaders.CONTENT_TYPE);
httpHeaders.remove(HttpHeaders.CONTENT_LENGTH);
httpHeaders.setContentLength(length);
httpHeaders.set(HttpHeaders.CONTENT_TYPE, contentType.toString());
// 设置CONTENT_TYPE
return httpHeaders;
}
@Override
public Flux<DataBuffer> getBody() {
return bodyFlux;
}
};
return chain.filter(exchange.mutate().request(mutatedRequest).build());
}
private JSONObject handleFormURLEncoded(String param) {
JSONObject jsonObject = new JSONObject();
String[] split = param.split("&");
for (String s : split) {
String[] split1 = s.split("=");
jsonObject.put(split1[0], split1[1]);
}
return jsonObject;
}
protected DataBuffer stringBuffer(String value) {
byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
buffer.write(bytes);
return buffer;
}
private String handleFormData(String str, String contentType) {
String sep = "--" + contentType.replace("multipart/form-data;boundary=", "");
String[] strs = str.split("\r\n");
boolean bankRow = false;// 空行
boolean keyRow = true;// name=xxx行
boolean append = false;// 内容是否拼接换行符
Map<String, String> params = new LinkedHashMap<>();// 这里保证接收顺序,所以用linkedhashmap
String s = null, key = null;
StringBuffer sb = new StringBuffer();
for (int i = 1, len = strs.length - 1; i < len; i++) {
s = strs[i];
if (keyRow) {
key = s.replace("Content-Disposition: form-data; name=", "");
key = key.substring(1, key.length() - 1);
keyRow = false;
bankRow = true;
sb = new StringBuffer();
append = false;
continue;
}
if (sep.equals(s)) {
keyRow = true;
if (null != key) {
params.put(key, sb.toString());
}
append = false;
continue;
}
if (bankRow) {
bankRow = false;
append = false;
continue;
}
if (append) {
sb.append("\r\n");
}
sb.append(s);
append = true;
}
if (null != key) {
params.put(key, sb.toString());
}
return JSON.toJSONString(params);// 这里是alibaba的fastjson,需要引入依赖
}
@Override
public int getOrder() {
return 1;
}
}
复制

转载请注明出处或者链接地址:https://www.qianduange.cn//article/6036.html
评论
还可以输入200
共0条数据,当前/页
发布的文章

JQuery中的load()、$

2024-05-10 08:05:15

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!