Gateway全局参数解密返回值加密:

项目中前端传入参数是解密的,所以在网关处要统一对加密参数解密,在转发到对应的微服务

请求参数解密统一处理:

Req拦截器中处理方法:
把这个方法里处理解密的Util类改成你自己的,我这里contentType约定是Json,你如果用其他的类型,自己改下MediaType.APPLICATION_JSON.:

@Component
@Slf4j
public class ReqFilter implements GlobalFilter, Ordered {


    private AntPathMatcher antPathMatcher= new AntPathMatcher();

    ServerHttpRequestDecorator decorate(ServerWebExchange exchange, HttpHeaders headers, CachedBodyOutputMessage outputMessage) {
        return new ServerHttpRequestDecorator(exchange.getRequest()) {
            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;
            }
            public Flux<DataBuffer> getBody() {
                return outputMessage.getBody();
            }
        };
    }


    private Mono<Void> returnMononew(GatewayFilterChain chain,ServerWebExchange exchange){
        return chain.filter(exchange).then(Mono.fromRunnable(()->{
        }));
    }
    private Mono<Void> readBody(ServerWebExchange exchange, GatewayFilterChain chain) {
        //重新构造request,参考ModifyRequestBodyGatewayFilterFactory
        ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());
        MediaType mediaType = exchange.getRequest().getHeaders().getContentType();
        //重点
        Mono<String> modifiedBody = serverRequest.bodyToMono(String.class).flatMap(body -> {
            //因为约定了终端传参的格式,所以只考虑json的情况,如果是表单传参,请自行增加
            if (MediaType.APPLICATION_JSON.isCompatibleWith(mediaType) || MediaType.APPLICATION_JSON_UTF8.isCompatibleWith(mediaType)) {
                String newBody = null;
                try{
                    // 解密body 此处调用你自己的解密方法
                    newBody = DecryptUtil.decipher(body);
                }catch (Exception e){
                    e.getMessage();
                }
                return Mono.just(newBody);
            }
            return Mono.empty();
        });
        BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);
        HttpHeaders headers = new HttpHeaders();
        headers.putAll(exchange.getRequest().getHeaders());
        //猜测这个就是之前报400错误的元凶,之前修改了body但是没有重新写content length
        headers.remove("Content-Length");
        //MyCachedBodyOutputMessage 这个类完全就是CachedBodyOutputMessage,只不过CachedBodyOutputMessage不是公共的
        CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers);
        return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> {
            ServerHttpRequest decorator = this.decorate(exchange, headers, outputMessage);
            return returnMononew(chain, exchange.mutate().request(decorator).build());
        }));
    }


    @SneakyThrows
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        String path = request.getURI().getPath(); // 当前调用方法的url
        HttpHeaders headers = request.getHeaders();
        log.info("HttpMethod:{},Url:{}", request.getMethod(), request.getURI().getRawPath());
        //  登录跳过网关验证,检查白名单(配置)最好把不拦截路径放入配置文件,此处通过正则
        if(antPathMatcher.match("/**/api/login/auth/**",path)){
            return readBody(exchange, chain);
        }
        // 处理参数
        MediaType contentType = headers.getContentType();
        long contentLength = headers.getContentLength();
        if (contentLength > 0) {
            if (MediaType.APPLICATION_JSON.equals(contentType) || MediaType.APPLICATION_JSON_UTF8.equals(contentType)) {
                return readBody(exchange, chain);
            }
        }
        return chain.filter(exchange);

    }

    @Override
    public int getOrder() {
        return 0;
    }
}

返回值统一加密处理:

在我注释的地方把加密方法改成你自己的加密方式,这里已经用DataBufferFactory解决了分段响应问题

@Component
@Slf4j
public class ResFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpResponse originalResponse = exchange.getResponse();
        DataBufferFactory bufferFactory = originalResponse.bufferFactory();
        ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                if (body instanceof Flux) {
                    Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;

                    return super.writeWith(fluxBody.buffer().map(dataBuffers -> {

                        DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                        DataBuffer join = dataBufferFactory.join(dataBuffers);

                        byte[] content = new byte[join.readableByteCount()];

                        join.read(content);
                        // 释放掉内存
                        DataBufferUtils.release(join);
                        // 返回值得字符串
                        String str = new String(content, Charset.forName("UTF-8"));
                        log.info(str);
                        // 把下面加密方法改成你自己的
                        String encryptStr = Base64.getEncoder().encodeToString(EncryptUtil.encrypt(str));
                        originalResponse.getHeaders().setContentLength(encryptStr.getBytes().length);

                        return bufferFactory.wrap(encryptStr.getBytes());
                    }));

                }
                // if body is not a flux. never got there.
                return super.writeWith(body);
            }
        };
        // replace response with decorator
        return chain.filter(exchange.mutate().response(decoratedResponse).build());
    }

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


Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐