From 006cbbb95327101809414f14954b22f7df2538a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=B7=E5=86=B7?= Date: Wed, 8 Jan 2020 21:56:41 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20Introducing=20new=20features.=20?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E6=95=8F=E6=84=9F=E5=8F=82=E6=95=B0=E6=94=AF?= =?UTF-8?q?=E6=8C=81=20post=20body?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gateway/filter/PasswordDecoderFilter.java | 125 +++++++++++++----- 1 file changed, 93 insertions(+), 32 deletions(-) diff --git a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/filter/PasswordDecoderFilter.java b/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/filter/PasswordDecoderFilter.java index 033c382fd..8c500bdc2 100644 --- a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/filter/PasswordDecoderFilter.java +++ b/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/filter/PasswordDecoderFilter.java @@ -25,76 +25,137 @@ import cn.hutool.crypto.Padding; import cn.hutool.crypto.symmetric.AES; import cn.hutool.http.HttpUtil; import com.pig4cloud.pigx.common.core.constant.SecurityConstants; -import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; +import org.springframework.cloud.gateway.filter.factory.rewrite.CachedBodyOutputMessage; +import org.springframework.cloud.gateway.support.BodyInserterContext; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.codec.HttpMessageReader; import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpRequestDecorator; import org.springframework.stereotype.Component; -import org.springframework.web.util.UriComponentsBuilder; +import org.springframework.web.reactive.function.BodyInserter; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.server.HandlerStrategies; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; -import java.net.URI; import java.nio.charset.StandardCharsets; -import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.function.Function; /** * @author lengleng - * @date 2018/7/15 + * @date 2020/1/8 * 密码解密工具类 + *

+ * 参考 ModifyRequestBodyGatewayFilterFactory 实现 */ @Slf4j @Component public class PasswordDecoderFilter extends AbstractGatewayFilterFactory { + private final List> messageReaders = HandlerStrategies.withDefaults().messageReaders(); + private static final String PASSWORD = "password"; private static final String KEY_ALGORITHM = "AES"; @Value("${security.encode.key:1234567812345678}") private String encodeKey; - @SneakyThrows - private static String decryptAES(String data, String pass) { - AES aes = new AES(Mode.CBC,Padding.NoPadding, - new SecretKeySpec(pass.getBytes(), KEY_ALGORITHM), - new IvParameterSpec(pass.getBytes())); - byte[] result = aes.decrypt(Base64.decode(data.getBytes(StandardCharsets.UTF_8))); - return new String(result, StandardCharsets.UTF_8); - } @Override public GatewayFilter apply(Object config) { return (exchange, chain) -> { ServerHttpRequest request = exchange.getRequest(); - // 不是登录请求,直接向下执行 if (!StrUtil.containsAnyIgnoreCase(request.getURI().getPath(), SecurityConstants.OAUTH_TOKEN_URL)) { return chain.filter(exchange); } - URI uri = exchange.getRequest().getURI(); - String queryParam = uri.getRawQuery(); - Map paramMap = HttpUtil.decodeParamMap(queryParam, CharsetUtil.UTF_8); + Class inClass = String.class; + Class outClass = String.class; + ServerRequest serverRequest = ServerRequest.create(exchange, + messageReaders); - String password = paramMap.get(PASSWORD); - if (StrUtil.isNotBlank(password)) { - try { - password = decryptAES(password, encodeKey); - } catch (Exception e) { - log.error("密码解密失败:{}", password); - return Mono.error(e); + // 解密生成新的报文 + Mono modifiedBody = serverRequest.bodyToMono(inClass) + .flatMap(decryptAES()); + + BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, outClass); + HttpHeaders headers = new HttpHeaders(); + headers.putAll(exchange.getRequest().getHeaders()); + headers.remove(HttpHeaders.CONTENT_LENGTH); + + headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE); + CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage( + exchange, headers); + return bodyInserter.insert(outputMessage, new BodyInserterContext()) + .then(Mono.defer(() -> { + ServerHttpRequest decorator = decorate(exchange, headers, + outputMessage); + return chain + .filter(exchange.mutate().request(decorator).build()); + })); + }; + } + + /** + * 原文解密 + * + * @return + */ + private Function decryptAES() { + return s -> { + // 构建前端对应解密AES 因子 + AES aes = new AES(Mode.CBC, Padding.NoPadding, + new SecretKeySpec(encodeKey.getBytes(), KEY_ALGORITHM), + new IvParameterSpec(encodeKey.getBytes())); + + // 获取请求密码并解密 + HashMap inParamsMap = HttpUtil.decodeParamMap((String) s, CharsetUtil.UTF_8); + byte[] result = aes.decrypt(Base64.decode(inParamsMap.get(PASSWORD) + .getBytes(StandardCharsets.UTF_8))); + String password = new String(result, StandardCharsets.UTF_8); + + // 返回修改后报文字符 + inParamsMap.put(PASSWORD, password.trim()); + return Mono.just(HttpUtil.toParams(inParamsMap)); + }; + } + + /** + * 报文转换 + * + * @return + */ + private 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 > 0) { + httpHeaders.setContentLength(contentLength); + } else { + httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked"); } - paramMap.put(PASSWORD, password.trim()); + return httpHeaders; } - URI newUri = UriComponentsBuilder.fromUri(uri) - .replaceQuery(HttpUtil.toParams(paramMap)) - .build(true) - .toUri(); - - ServerHttpRequest newRequest = exchange.getRequest().mutate().uri(newUri).build(); - return chain.filter(exchange.mutate().request(newRequest).build()); + @Override + public Flux getBody() { + return outputMessage.getBody(); + } }; } }