springcloud-gateway中修改body内容问题以及上下文存入信息打印日志

13

1.首先需求是要对网关通过的所有请求进行解密,客户端进行加密

2.其次gatewaybody不可以进行重复读取,需要存入上下文变量

3.还要打印出具体的接口日志,入参,方式以及出参(解密后的)

  1. 新建上下文实体
@Data
public class GatewayContext {
    public static final String CACHE_GATEWAY_CONTEXT = "cacheGatewayContext";

    /**
     * cache headers
     */
    private HttpHeaders headers;

    /**
     * cache json body
     */
    private String cacheBody;
    /**
     * cache formdata
     */
    private MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();

    /**
     * ipAddress
     */
    private String ipAddress;

    /**
     * path
     */
    private String path;
}
  1. 再建立解密并且存入上下文变量(解密自行实现)
@Slf4j
@Component
public class MyDecryptFilter implements GlobalFilter, Ordered {

    private static final List<HttpMessageReader<?>> MESSAGE_READERS = HandlerStrategies.withDefaults().messageReaders();

    /**
     * 请求头
     */
    public static final String HEADER_CONTENT_LENGTH = "Content-Length";

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        if (Objects.equals(exchange.getRequest().getMethod(), HttpMethod.POST)) {
            ServerRequest serverRequest = ServerRequest.create(exchange, MESSAGE_READERS);
            MediaType mediaType = exchange.getRequest().getHeaders().getContentType();
            //重点
            Mono<String> modifiedBody = serverRequest.bodyToMono(String.class).flatMap(body -> {
                // post只考虑json请求验签(其他方式请自行实现)
                if (MediaType.APPLICATION_JSON.isCompatibleWith(mediaType) || MediaType.APPLICATION_JSON_UTF8.isCompatibleWith(mediaType)) {
                    String newBody = "{\"code\":500,\"msg\":\"请求参数签名验证失败!\"}";
                    try {
                        JSONObject jsonObject = JSON.parseObject(body);
                        newBody = verifySign(jsonObject);
                    } catch (Exception e) {
                        //do nothing
                    }
                    //将验签后的变量存入上下文
                    putGatewayContext(exchange, newBody);
                    return Mono.just(newBody);
                }
                return Mono.empty();
            });

            BodyInserter<Mono<String>, ReactiveHttpOutputMessage> bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);
            //获取请求头
            HttpHeaders headers = new HttpHeaders();
            headers.putAll(exchange.getRequest().getHeaders());
            headers.remove(HEADER_CONTENT_LENGTH);

            CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers);

            return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> {
                ServerHttpRequest decorator = this.decorate(exchange, headers, outputMessage);
                return returnMono(chain, exchange.mutate().request(decorator).build());
            }));
        } else {
            return chain.filter(exchange);
        }
    }

    /**
     * 将验签后的json存入上下文,方面调用链下的过滤器获取
     *
     * @param exchange exchange
     */
    private void putGatewayContext(ServerWebExchange exchange, String requestBody) {
        ServerHttpRequest request = exchange.getRequest();
        HttpHeaders headers = request.getHeaders();
        GatewayContext gatewayContext = new GatewayContext();

        String path = request.getPath().pathWithinApplication().value();
        gatewayContext.setPath(path);
        gatewayContext.getFormData().addAll(request.getQueryParams());
        gatewayContext.setIpAddress(String.valueOf(request.getRemoteAddress()));
        gatewayContext.setHeaders(headers);
        gatewayContext.setCacheBody(requestBody);
        //将上下文内容存入exchange
        exchange.getAttributes().put(GatewayContext.CACHE_GATEWAY_CONTEXT, gatewayContext);
    }

    /**
     * 验证签名
     *
     * @param jsonObject json对象
     * @return 解密后的json字符串
     */
    private String verifySign(JSONObject jsonObject) {
        //todo 进行验签,然后转为解密后的JSON
        return JSON.toJSONString(jsonObject);
    }

    private Mono<Void> returnMono(GatewayFilterChain chain, ServerWebExchange exchange) {
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
//            log.info("状态码:{}", Objects.requireNonNull(exchange.getResponse().getStatusCode()).value());
        }));
    }

    ServerHttpRequestDecorator decorate(ServerWebExchange exchange, HttpHeaders headers, CachedBodyOutputMessage outputMessage) {
        return new ServerHttpRequestDecorator(exchange.getRequest()) {
            @Override
            public HttpHeaders getHeaders() {
                long contentLength = headers.getContentLength();
                HttpHeaders httpHeaders = new HttpHeaders();
                httpHeaders.putAll(super.getHeaders());
                if (contentLength > 0L) {
                    httpHeaders.setContentLength(contentLength);
                } else {
                    httpHeaders.set("Transfer-Encoding", "chunked");
                }
                return httpHeaders;
            }

            @Override
            public Flux<DataBuffer> getBody() {
                return outputMessage.getBody();
            }
        };
    }

    @Override
    public int getOrder() {
        return -300;
    }
}