/ java / 282浏览

网关统一参数加解密

1.GlobalRequestBodyDecodeFilter.java

package com.itlong.cloud.filters;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Value;
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.http.HttpHeaders;
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.bind.annotation.RequestMethod;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

@Component
@Slf4j
public class GlobalRequestBodyDecodeFilter implements GlobalFilter, Ordered {
    @Value("${" + PlatformConstants.GatewayConfig.WEB_SECRET_KEY + "}")
    String webSecretKey;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        MediaType contentType = request.getHeaders().getContentType();
        String method = request.getMethodValue();
        MDC.clear();
        if (RequestMethod.POST.name().equals(method)) {
            return DataBufferUtils.join(exchange.getRequest().getBody())
                    .flatMap(dataBuffer -> {
                        byte[] bytes = new byte[dataBuffer.readableByteCount()];
                        dataBuffer.read(bytes);
                        String bodyString = "";
                        try {
                            bodyString = new String(bytes, "utf-8");
                            bodyString = decryptData(contentType, bodyString, exchange);
                        } catch (UnsupportedEncodingException e) {
                            log.error("获取请求参数失败!{},{}", ErrorTypeEnum.PARAMETER_ANOMALY, e.getMessage());
                        }
                        DataBufferUtils.release(dataBuffer);
                        String finalBodyString = bodyString;
                        Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
                            DataBuffer buffer = exchange.getResponse().bufferFactory()
                                    .wrap(finalBodyString.getBytes(StandardCharsets.UTF_8));
                            return Mono.just(buffer);
                        });

                        ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
                                exchange.getRequest()) {
                            @Override
                            public Flux<DataBuffer> getBody() {
                                return cachedFlux;
                            }

                            //复写getHeaders方法
                            @Override
                            public HttpHeaders getHeaders() {
                                HttpHeaders httpHeaders = new HttpHeaders();
                                httpHeaders.putAll(super.getHeaders());
                                httpHeaders.remove(HttpHeaders.CONTENT_LENGTH);
                                httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
                                return httpHeaders;
                            }

                            @Override
                            public URI getURI() {
                                URI uri = exchange.getRequest().getURI();
                                URI newUri = UriComponentsBuilder.fromUri(uri)
                                        .build(true)
                                        .toUri();
                                return newUri;
                            }
                        };
                        return chain.filter(exchange.mutate().request(mutatedRequest)
                                .build());
                    });
        }
        if (RequestMethod.GET.name().equals(method)) {
            URI uri = exchange.getRequest().getURI();
            String query = "";
            String originalQuery = uri.getRawQuery();
            if (null != originalQuery && originalQuery.contains(PlatformConstants.GatewayConfig.ENCRYPT_SCRIPT_KEY)) {
                try {
                    //get为url传参 token需要encode
                    query = getFormData(originalQuery, true, exchange);
                } catch (Exception e) {
                    log.error("get请求解密数据失败!{},{}", ErrorTypeEnum.SYSTEM_ANOMALY, e.getMessage());
                }
            }
            URI newUri = UriComponentsBuilder.fromUri(uri)
                    .replaceQuery(query)
                    .build(true)
                    .toUri();
            ServerHttpRequest build = exchange.getRequest().mutate().uri(newUri).build();
            return chain.filter(exchange.mutate().request(build).build());
        }
        return chain.filter(exchange);
    }

    /**
     * 解密数据
     *
     * @param contentType
     * @param bodyJson
     * @return
     */
    private String decryptData(MediaType contentType, String bodyJson, ServerWebExchange exchange) {
        String encryptScript;
        String data = "";
        try {
            if (bodyJson.contains(PlatformConstants.GatewayConfig.ENCRYPT_SCRIPT_KEY)) {
                if (MediaType.APPLICATION_JSON.isCompatibleWith(contentType) || MediaType.APPLICATION_JSON_UTF8.isCompatibleWith(contentType)) {
                    JSONObject json = JSON.parseObject(bodyJson);
                    encryptScript = json.getString(PlatformConstants.GatewayConfig.ENCRYPT_SCRIPT_KEY);
                    log.info("encryptScript=======>:{}", encryptScript);
                    String encryptResult = DesEncryptUtil.aesDecrypt(URLDecoder.decode(encryptScript, "utf-8"), webSecretKey);
                    json = JSON.parseObject(encryptResult);
                    log.info("encryptResult=======>:{}", encryptResult);
                    setRequestId(json, exchange);
                    exchange.getAttributes().put(PlatformConstants.GatewayConfig.CACHED_REQUEST_BODY, json);
                    return json.toJSONString();
                }
                if (MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(contentType)) {
                    return getFormData(bodyJson, false, exchange);
                }
            }
        } catch (Exception e) {
            log.error("请求解密数据失败!{},{}", ErrorTypeEnum.SYSTEM_ANOMALY, e.getMessage());
        }
        return data;
    }

    /**
     * <desc>
     * 设置请求ID
     * </desc>
     *
     * @param json
     * @param exchange
     * @return void
     * @author maju
     * @createDate 2021/7/14
     */

    private void setRequestId(JSONObject json, ServerWebExchange exchange) {
        String requestId = json.getString("requestId");
        if (StringUtils.isNotEmpty(requestId)) {
        } else {
            requestId = IdUtil.fastSimpleUUID();
            json.put("addParas", "requestId");
            json.put("requestId", requestId);
        }
        exchange.getAttributes().put(PlatformConstants.Public.REQUEST_ID, requestId);
        MDC.put(PlatformConstants.Public.REQUEST_ID, requestId);
    }

    /**
     * 获取form数据
     *
     * @param bodyJson
     * @param isEncode
     * @return
     * @throws Exception
     */
    private String getFormData(String bodyJson, boolean isEncode, ServerWebExchange exchange) throws Exception {
        String encryptScript;
        encryptScript = bodyJson.split("&")[0].split("=")[1];
        log.info("encryptScript=======>:{}", encryptScript);
        String encryptResult = DesEncryptUtil.aesDecrypt(URLDecoder.decode(encryptScript, "utf-8"), webSecretKey);
        JSONObject json = JSON.parseObject(encryptResult);
        setRequestId(json, exchange);
        log.info("encryptResult=======>:{}", encryptResult);
        StringBuilder sb = new StringBuilder();
        json.forEach((k, v) -> {
            try {
                if (isEncode) {
                    sb.append(k + "=" + URLEncoder.encode(v.toString(), "utf-8"));
                } else {
                    sb.append(k + "=" + v);
                }
            } catch (UnsupportedEncodingException e) {
                log.error("参数encode异常!{},{}", ErrorTypeEnum.SYSTEM_ANOMALY, e.getMessage());
            }
            sb.append("&");
        });
        sb.deleteCharAt(sb.lastIndexOf("&"));
        exchange.getAttributes().put(PlatformConstants.GatewayConfig.CACHED_REQUEST_BODY, json);
        return sb.toString();
    }

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

2.GlobalResponseBodyEncodeFilter.java

package com.itlong.cloud.filters;

import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.reactivestreams.Publisher;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Value;
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.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 对所有的response请求的body进行加密
 */
@Component
@Slf4j
public class GlobalResponseBodyEncodeFilter implements GlobalFilter, Ordered {


    @Value("${" + PlatformConstants.GatewayConfig.WEB_SECRET_KEY + "}")
    String webSecretKey;
    private static Joiner joiner = Joiner.on("");//将 List 数据以""分隔进行拼接

    @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) {
                //设置响应打印请求ID
                String requestId = exchange.getAttributeOrDefault(PlatformConstants.Public.REQUEST_ID, "");
                MDC.put(PlatformConstants.Public.REQUEST_ID, requestId);
                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 result = null;
                        try {
                            result = new String(content, Charset.forName("UTF-8"));
                        } catch (Exception e) {
                            log.error("获取响应异常!:{},{}", ErrorTypeEnum.SYSTEM_ANOMALY, e.getMessage());
                        }
                        // 对响应体进行加密
                        JSONObject rjson = new JSONObject();
                        try {
                            log.info("result==========>:" + result);
                            //签名且加密
                            SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
                            Date date = new Date();
                            String createTime = df.format(date);
                            JSONObject json = new JSONObject();
                            Map<String, Object> jsonToMap = new HashMap<>();
                            jsonToMap.put("data", result);
                            String sign = Md5EncryptUtil.cloudDeviceMd5(jsonToMap, createTime, webSecretKey);
                            json.put("allData", result);
                            json.put("createTime", createTime);
                            json.put("sign", sign);
                            rjson.put("encryptScript", DesEncryptUtil.aesEncryptSDK(json.toJSONString(), webSecretKey));
                        } catch (Exception e) {
                            e.printStackTrace();
                            log.error("加密异常:{},{}", ErrorTypeEnum.SYSTEM_ANOMALY, e.getMessage());
                            throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "响应体加密异常");
                        }
                        return bufferFactory.wrap(rjson.toJSONString().getBytes(StandardCharsets.UTF_8));
                    }));
                }
                return super.writeWith(body);
            }
        };
        return chain.filter(exchange.mutate().response(decoratedResponse).build());
    }

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