首页 前端知识 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 前端知识 前端哥 132 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
评论
发布的文章

JQuery中的load()、$

2024-05-10 08:05:15

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