diff --git a/fizz-plugin/src/main/java/we/plugin/grayrelease/GrayReleasePlugin.java b/fizz-plugin/src/main/java/we/plugin/grayrelease/GrayReleasePlugin.java new file mode 100644 index 0000000..3318eca --- /dev/null +++ b/fizz-plugin/src/main/java/we/plugin/grayrelease/GrayReleasePlugin.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2021 the original author or authors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package we.plugin.grayrelease; + +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.symmetric.SymmetricAlgorithm; +import cn.hutool.crypto.symmetric.SymmetricCrypto; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.ThreadContext; +import org.reactivestreams.Publisher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.NettyDataBuffer; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; +import we.config.SystemConfig; +import we.dedicated_line.DedicatedLineService; +import we.plugin.FizzPluginFilterChain; +import we.plugin.requestbody.RequestBodyPlugin; +import we.spring.http.server.reactive.ext.FizzServerHttpRequestDecorator; +import we.spring.http.server.reactive.ext.FizzServerHttpResponseDecorator; +import we.util.Consts; +import we.util.NettyDataBufferUtils; +import we.util.WebUtils; + +import javax.annotation.Resource; +import java.util.Map; + +/** + * @author hongqiaowei + */ + +@Component(GrayReleasePlugin.GRAY_RELEASE_PLUGIN) +public class GrayReleasePlugin extends RequestBodyPlugin { + + private static final Logger log = LoggerFactory.getLogger(GrayReleasePlugin.class); + + public static final String GRAY_RELEASE_PLUGIN = "GrayReleasePlugin"; + + @Resource + private SystemConfig systemConfig; + + @Resource + private DedicatedLineService dedicatedLineService; + + @Override + public Mono doFilter(ServerWebExchange exchange, Map config) { + String traceId = WebUtils.getTraceId(exchange); + ThreadContext.put(Consts.TRACE_ID, traceId); + try { + // LogService.setBizId(traceId); + String dedicatedLineId = WebUtils.getDedicatedLineId(exchange); + String cryptoKey = dedicatedLineService.getRequestCryptoKey(dedicatedLineId); + + FizzServerHttpRequestDecorator request = (FizzServerHttpRequestDecorator) exchange.getRequest(); + return request.getBody().defaultIfEmpty(NettyDataBufferUtils.EMPTY_DATA_BUFFER).single().flatMap(body -> { + if (body != NettyDataBufferUtils.EMPTY_DATA_BUFFER && systemConfig.fizzDedicatedLineClientRequestCrypto()) { + byte[] bodyBytes = request.getBodyBytes(); + request.setBody(decrypt(bodyBytes, cryptoKey)); + request.getHeaders().remove(HttpHeaders.CONTENT_LENGTH); + } + + ServerHttpResponse original = exchange.getResponse(); + FizzServerHttpResponseDecorator fizzServerHttpResponseDecorator = new FizzServerHttpResponseDecorator(original) { + @Override + public Publisher writeWith(DataBuffer remoteResponseBody) { + if (remoteResponseBody == null || remoteResponseBody == NettyDataBufferUtils.EMPTY_DATA_BUFFER) { + return Mono.empty(); + } else { + if (StringUtils.isNotBlank(cryptoKey)) { + getDelegate().getHeaders().remove(HttpHeaders.CONTENT_LENGTH); + byte[] bytes = remoteResponseBody.asByteBuffer().array(); + NettyDataBuffer from = NettyDataBufferUtils.from(encrypt(bytes, cryptoKey)); + return Mono.just(from); + } else { + return Mono.just(remoteResponseBody); + } + } + } + }; + ServerWebExchange build = exchange.mutate().response(fizzServerHttpResponseDecorator).build(); + return FizzPluginFilterChain.next(build); + }); + + } catch (Exception e) { + // log.error("{} {} Exception", traceId, DEDICATED_LINE_CODEC_PLUGIN_FILTER, LogService.BIZ_ID, traceId, e); + log.error("{} {} Exception", traceId, GRAY_RELEASE_PLUGIN, e); + String respJson = WebUtils.jsonRespBody(HttpStatus.INTERNAL_SERVER_ERROR.value(), + HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase(), traceId); + return WebUtils.response(exchange, HttpStatus.INTERNAL_SERVER_ERROR, null, respJson); + } + } + + /*public String encrypt(String data, String secretKey) { + if (StringUtils.isBlank(data)) { + return data; + } + byte[] key = SecureUtil.decode(secretKey); + SymmetricCrypto symmetric = new SymmetricCrypto(SymmetricAlgorithm.AES, key); + return symmetric.encryptBase64(data); + }*/ + + public byte[] encrypt(byte[] data, String secretKey) { + byte[] key = SecureUtil.decode(secretKey); + SymmetricCrypto symmetric = new SymmetricCrypto(SymmetricAlgorithm.AES, key); + return symmetric.encrypt(data); + } + + /*public String decrypt(String data, String secretKey) { + if (StringUtils.isBlank(data)) { + return data; + } + byte[] key = SecureUtil.decode(secretKey); + SymmetricCrypto symmetric = new SymmetricCrypto(SymmetricAlgorithm.AES, key); + return symmetric.decryptStr(data); + }*/ + + public byte[] decrypt(byte[] data, String secretKey) { + byte[] key = SecureUtil.decode(secretKey); + SymmetricCrypto symmetric = new SymmetricCrypto(SymmetricAlgorithm.AES, key); + return symmetric.decrypt(data); + } +}