> 文章列表 > JAVA开发(通过网关gateway过滤器进行返回结果加密)

JAVA开发(通过网关gateway过滤器进行返回结果加密)

JAVA开发(通过网关gateway过滤器进行返回结果加密)

在对C的网站或者APP后端接口中,参数的传输往往需要加密传输。这时我们 可以通过springcloud的网关过滤器进行统一的控制。

网关过滤器的执行顺序:

请求进入网关会碰到三类过滤器:当前路由过滤器、DefaultFilter、GlobalFilter。

请求路由后,会将当前路由过滤器和DefaultFilter、GlobalFilter,合并到一个过滤器链(集合)中,排序后依次执行每个过滤器

过滤器执行顺序
1.每一个过滤器都必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前。
2.GlobalFilter通过实现Ordered接口,或者添加@Order注解来指定order值,由我们自己指定
3.路由过滤器和defaultFilter的order由Spring指定,默认是按照声明顺序从1递增。

4.当过滤器的order值一样时,会按照 defaultFilter > 路由过滤器 > GlobalFilter的顺序执行。

可以参考下面几个类的源码来查看:
org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#getFilters()方法是先加载defaultFilters,然后再加载某个route的filters,然后合并。

org.springframework.cloud.gateway.handler.FilteringWebHandler#handle()方法会加载全局过滤器,与前面的过滤器合并后根据order排序,组织过滤器链
路由过滤器、defaultFilter、全局过滤器的执行顺序?
1.order值越小,优先级越高
2.当order值一样时,顺序是defaultFilter最先,然后是局部的路由过滤器,最后是全局过滤器

package com.tsl.serviceingateway.sso;import com.alibaba.fastjson.JSONObject;
import com.tsl.serviceingateway.sso.util.AESUtil;
import com.tsl.serviceingateway.sso.util.Sm4Util;
import io.netty.buffer.ByteBufAllocator;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.core.io.buffer.NettyDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
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.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLDecoder;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;/*** 参数加密传输*/
@Component
public class ParamsEncryptionFilter implements GlobalFilter, Ordered {static Logger logger = LoggerFactory.getLogger(ParamsEncryptionFilter.class);@SneakyThrows@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest serverHttpRequest = exchange.getRequest();HttpMethod method = serverHttpRequest.getMethod();String encryptionType = serverHttpRequest.getHeaders().getFirst("encryptionType");URI uri = serverHttpRequest.getURI();MediaType mediaType = serverHttpRequest.getHeaders().getContentType();if (encryptionType != null) {if (method == HttpMethod.POST || method == HttpMethod.PUT) {//从请求里获取Post请求体String bodyStr = resolveBodyFromRequest(serverHttpRequest);logger.info("PUT OR POST bodyStr: " + bodyStr);//密文参数String cipherParams = "";//明文参数String plainParams = "";if (bodyStr != null) {// 根据请求方法类型获取密文cipherParams = getCiphertextByMediaType(bodyStr, mediaType);//解密logger.info("PUT OR POST ciphertext  parameters: " + cipherParams);plainParams = decodeParamsBytype(encryptionType, cipherParams);//非法非法加密处理,不进行解密操作if ("-1".equals(plainParams)) {return chain.filter(exchange);}logger.info("PUT OR POST plaintext parameters: " + plainParams);//封装request,传给下一级ServerHttpRequest request = serverHttpRequest.mutate().uri(uri).build();DataBuffer bodyDataBuffer = stringBuffer(plainParams);Flux<DataBuffer> bodyFlux = Flux.just(bodyDataBuffer);request = new ServerHttpRequestDecorator(request) {@Overridepublic Flux<DataBuffer> getBody() {return bodyFlux;}};// 构建新的请求头HttpHeaders headers = new HttpHeaders();headers.putAll(exchange.getRequest().getHeaders());// 重新设置CONTENT_LENGTHint length = plainParams.getBytes().length;headers.remove(HttpHeaders.CONTENT_LENGTH);headers.setContentLength(length);request = new ServerHttpRequestDecorator(request) {@Overridepublic HttpHeaders getHeaders() {return headers;}};return chain.filter(exchange.mutate().request(request).build());}} else if (method == HttpMethod.GET || method == HttpMethod.DELETE) {try {MultiValueMap<String, String> requestQueryParams = serverHttpRequest.getQueryParams();logger.info("GET OR DELETE ciphertext  parameters: " + requestQueryParams.get("params").get(0));String params = requestQueryParams.get("params").get(0);//解密params = decodeParamsBytype(encryptionType, params);//非法非法加密处理,不进行解密操作if ("-1".equals(params)) {return chain.filter(exchange);}logger.info("GET OR DELETE plaintext parameters: " + params);// 封装URLURI plaintUrl = new URI(uri.getScheme(), uri.getAuthority(),uri.getPath(), params, uri.getFragment());//封装request,传给下一级ServerHttpRequest request = serverHttpRequest.mutate().uri(plaintUrl).build();logger.info("get OR delete plaintext request.getQueryParams(): " + request.getQueryParams());return chain.filter(exchange.mutate().request(request).build());} catch (Exception e) {return chain.filter(exchange);}}}return chain.filter(exchange);}/*** 根据请求方法类型获取密文*/private String getCiphertextByMediaType(String bodyStr, MediaType mediaType) throws UnsupportedEncodingException {//json请求if (mediaType.equals(MediaType.APPLICATION_JSON)) {JSONObject bodyJson = JSONObject.parseObject(bodyStr);return bodyJson.getString("params");}//form请求else if (mediaType.equals(MediaType.MULTIPART_FORM_DATA) || mediaType.equals(MediaType.APPLICATION_FORM_URLENCODED)) {Map<String, String> keyValues = urlSplit(bodyStr);return URLDecoder.decode(keyValues.get("params"), "UTF-8");} else {return "-1";}}/*** 解密过滤器必须在所有过滤器之前,否后后续过滤器获取参数会报错* 如果有的其他的过滤器添加请调整过滤器顺序*/@Overridepublic int getOrder() {return -2;}//根据类型进行解密private String decodeParamsBytype(String type, String params) throws Exception {if ("BA".equals(type)) {//BASE64解密return new String(Base64.getDecoder().decode(params));} else if ("AE".equals(type)) {//AES128解密return AESUtil.aesDecrypt(params);} else if ("SM".equals(type)) {//SM4解密return Sm4Util.decryptEcb(params);} else {//非法解密return "-1";}}private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) {//获取请求体Flux<DataBuffer> body = serverHttpRequest.getBody();AtomicReference<String> bodyRef = new AtomicReference<>();body.subscribe(buffer -> {CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());DataBufferUtils.release(buffer);bodyRef.set(charBuffer.toString());});//获取request bodyreturn bodyRef.get();}private DataBuffer stringBuffer(String value) {byte[] bytes = value.getBytes(StandardCharsets.UTF_8);NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);buffer.write(bytes);return buffer;}/*** 解析出url参数中的键值对* 如 "Action=del&id=123",解析出Action:del,id:123存入map中** @param params url地址* @return url请求参数部分*/private static Map<String, String> urlSplit(String params) {Map<String, String> mapRequest = new HashMap<>();String[] arrSplit = null;if (params == null) {return mapRequest;}arrSplit = params.split("[&]");for (String strSplit : arrSplit) {String[] arrSplitEqual = null;arrSplitEqual = strSplit.split("[=]");//解析出键值if (arrSplitEqual.length > 1) {//正确解析mapRequest.put(arrSplitEqual[0], arrSplitEqual[1]);} else if (arrSplitEqual[0] != "") {//只有参数没有值,不加入mapRequest.put(arrSplitEqual[0], "");}}return mapRequest;}public static void main(String[] args) throws Exception {String params = "accountName=superadmin&password=123123";//base64String encodeParams = Base64.getEncoder().encodeToString(params.getBytes());logger.info("BASE64 encodeParams: " + encodeParams);String decoderParams = new String(Base64.getDecoder().decode(encodeParams));logger.info("BASE64 decoderParams: " + decoderParams);//aes128String aesEncodeParams = AESUtil.aesEncrypt(params);logger.info("aesEncodeParams: " + aesEncodeParams);String aesdecodeParams = AESUtil.aesDecrypt(aesEncodeParams);logger.info("aesdecodeParams: " + aesdecodeParams);//国密sm4String sm4EncodeParams = Sm4Util.encryptEcb(params);logger.info("sm4EncodeParams: " + sm4EncodeParams);String sm4DecodeParams = Sm4Util.decryptEcb(sm4EncodeParams);logger.info("sm4DecodeParams: " + sm4DecodeParams);}

或者

 ServerHttpResponse originalResponse = exchange.getResponse();DataBufferFactory bufferFactory = originalResponse.bufferFactory();ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {@Overridepublic 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);// 解析返回参数JSONObject jsonObject = JSONUtil.parseObj(str);ResponseData responseData = JSONUtil.toBean(jsonObject, ResponseData.class);if (responseData.isEncrypt()) {str = AesUtil.hutoolEncrpt(str, AES_KEY);originalResponse.getHeaders().setContentLength(str.getBytes().length);}return bufferFactory.wrap(str.getBytes());}));}// if body is not a flux. never got there.return super.writeWith(body);}};// replace response with decoratorreturn chain.filter(exchange.mutate().response(decoratedResponse).build());}