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

news2024/11/28 7:38:25

在对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
    @Override
    public 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) {
                        @Override
                        public Flux<DataBuffer> getBody() {
                            return bodyFlux;
                        }
                    };
                    // 构建新的请求头
                    HttpHeaders headers = new HttpHeaders();
                    headers.putAll(exchange.getRequest().getHeaders());
                    // 重新设置CONTENT_LENGTH
                    int length = plainParams.getBytes().length;
                    headers.remove(HttpHeaders.CONTENT_LENGTH);
                    headers.setContentLength(length);
                    request = new ServerHttpRequestDecorator(request) {
                        @Override
                        public 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);
                    // 封装URL
                    URI 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";
        }
    }

    /**
     * 解密过滤器必须在所有过滤器之前,否后后续过滤器获取参数会报错
     * 如果有的其他的过滤器添加请调整过滤器顺序
     */
    @Override
    public 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 body
        return 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";
        //base64
        String encodeParams = Base64.getEncoder().encodeToString(params.getBytes());
        logger.info("BASE64 encodeParams: " + encodeParams);
        String decoderParams = new String(Base64.getDecoder().decode(encodeParams));
        logger.info("BASE64 decoderParams: " + decoderParams);

        //aes128
        String aesEncodeParams = AESUtil.aesEncrypt(params);
        logger.info("aesEncodeParams: " + aesEncodeParams);
        String aesdecodeParams = AESUtil.aesDecrypt(aesEncodeParams);
        logger.info("aesdecodeParams: " + aesdecodeParams);

        //国密sm4
        String 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) {
			@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);
						// 解析返回参数
						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 decorator
		return chain.filter(exchange.mutate().response(decoratedResponse).build());
		
	}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/423336.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ChatGPT团队中,3个清华学霸,1个北大学霸,共9位华人

众所周知&#xff0c;美国硅谷其实有着众多的华人&#xff0c;哪怕是芯片领域&#xff0c;华为也有着一席之地&#xff0c;比如AMD 的 CEO 苏姿丰、Nvidia 的 CEO 黄仁勋 都是华人。 还有更多的美国著名的科技企业中&#xff0c;都有着华人的身影&#xff0c;这些华人&#xff…

Vue组件化编程【Vue】

2.Vue 组件化编程 2.1 模块与组件、模块化与组件化 2.1.1 模块 理解&#xff1a;向外提供特定功能的js程序&#xff0c;一般就是一个js文件为什么&#xff1a;js文件很多很复杂作用&#xff1a;复用js、简化js的编写、提高js运行效率。 2.1.2 组件 理解&#xff1a;用来实…

Linux搭建Web服务器(二)——Web Server 与 HTTP

目录 0x01 Web Server 静态网络服务器&#xff08;static web server&#xff09; 动态网络服务器&#xff08;dynamic web server&#xff09; 0x02 HTTP协议 HTTP概述 HTTP工作原理 HTTP请求报文格式 HTTP响应报文格式 0x01 Web Server 一个Web Server就是一个服务器…

我们要被淘汰了?从科技变革看"ChatGPT"与"无代码开发"

现在只要一上网&#xff0c;就能看见GPT都在说“好厉害”、“太牛了”、“新技术要诞生了”、“我们人类要被淘汰了”之类的话题。但是这伟大的技术变革到底给我们带来了什么呢&#xff1f;答案好像又比较模糊。现在ChatGPT的代写、问答&#xff0c;以及开始做的搜索、办公是目…

sql查询语句-01

1.单表查询 ◆限制显示结果 使用limit限制显示的行数&#xff0c;分页函数limit m,n,从m1行开始显示n条记录 例&#xff1a;查询选修课程成绩排在前5的学生的学号和成绩。 select sno,score from SCorder by score desc limit 5;limit 1,3 零是第一条 ◆汇总数据(聚集函数&…

coinex06 // 前端数据 -> ringbuffer -> cpu

目录 0. 逻辑树 1 exchange-service 发送消息 1.1 exchange-service 添加依赖 1.2. yml配置文件 1.3. Source 1.4. 配置类 1.5. 发送消息到撮合引擎 service -> impl -> EntrustOrderServiceImpl 1.6. recket-server:8080 2. match-server 接收数据 2.1 数据转…

【SQL 必知必会】- 第十七课 创建和操纵表

目录 17.1 创建表 17.1.1 表创建基础 替换现有的表 17.1.2 使用NULL值 主键和NULL 值 理解NULL 17.1.3 指定默认值 使用DEFAULT 而不是NULL 值 17.2 更新表 小心使用ALTER TABLE 17.3 删除表 使用关系规则防止意外删除 17.4 重命名表 17.5 小结 这一课讲授创建、更改和删除…

【MyBatis Plus】002 -- 通用CRUD(插入、更新、删除、查询)

目录 3、通用CRUD 3.1 插入操作 3.1.1 方法定义 3.1.2 测试用例 3.1.3 测试 3.1.4 TableField 3.2 更新操作 3.2.1 根据id更新 3.2.2 根据条件更新 3.3 删除操作 3.3.1 根据id删除&#xff08;deleteById&#xff09; 3.3.2 根据Map删除数据&#xff08;deleteByMap&#xff09…

程序员必备技巧:Git 和 GitHub 中高效地将单个文件还原为特定提交

Git 和 GitHub 用于存储您的旧代码&#xff0c;允许您在出现问题时回滚并安全地恢复以前的准确代码。 与其他开发人员协作时&#xff0c;了解如何将单个文件恢复为特定提交也变得至关重要。这是因为&#xff0c;在处理某个功能时&#xff0c;您可能需要修改不相关的文件来测试…

Cursor编程初体验,搭载GPT-4大模型,你的AI助手,自然语言编程来了

背景 这两天体验了下最新生产力工具Cursor&#xff0c;基于最新的 GPT-4 大模型&#xff0c;目前免费&#xff0c;国内可访问&#xff0c;不限次数&#xff0c;跨平台&#xff0c;你确定不来体验一把&#xff1f;官方的 Slogan &#xff1a; Build Software. Fast. Write, edi…

【CSS】课程网站 Banner 制作 ② ( Banner 栏版心盒子测量 | Banner 版心盒子模型左侧导航栏代码示例 )

文章目录一、Banner 栏版心盒子测量1、测量版心元素尺寸2、课程表测量二、Banner 版心盒子模型左侧导航栏代码示例1、HTML 标签结构2、CSS 样式3、展示效果一、Banner 栏版心盒子测量 1、测量版心元素尺寸 拉四条辅助线 , 将版心包起来 , 可以测量 Banner 条版心的尺寸为 1200 …

Nginx网站服务详解(第二部分:Nginx服务的主配置文件 ——nginx.conf)

1. 全局配置的六个模块简介 全局块&#xff1a;全局配置&#xff0c;对全局生效&#xff1b;events块&#xff1a;配置影响 Nginx 服务器与用户的网络连接&#xff1b;http块&#xff1a;配置代理&#xff0c;缓存&#xff0c;日志定义等绝大多数功能和第三方模块的配置&…

SLBR通过自校准的定位和背景细化来去除可见的水印

一、简要介绍 本文简要介绍了论文“Visible Watermark Removal via Self-calibrated Localization and Background Refinement ”的相关工作。在图像上叠加可见的水印&#xff0c;为解决版权问题提供了一种强大的武器。现代的水印去除方法可以同时进行水印定位和背景恢复&#…

C++ 实现 Matlab 的 lp2lp 函数

文章目录1. matlab 的 lp2lp 函数的作用2. matlab 的 lp2lp 函数的使用方法3. C 实现3.1 complex.h 文件3.2 lp2lp.h 文件4. 测试结果4.1 测试文件4.2 测试3阶的情况4.3 测试9阶的情况1. matlab 的 lp2lp 函数的作用 去归一化 H(s) 的分母 2. matlab 的 lp2lp 函数的使用方法…

人脸识别经典网络-MTCNN(含Python源码实现)

人脸检测-mtcnn 本文参加新星计划人工智能赛道&#xff1a;https://bbs.csdn.net/topics/613989052 文章目录人脸检测-mtcnn1. 人脸检测1.1 人脸检测概述1.2 人脸检测的难点1.3 人脸检测的应用场景2. mtcnn2.1 mtcnn概述2.2 mtcnn的网络结构2.3 图像金字塔2.4 P-Net2.5 R-Net2…

为什么说过早优化是万恶之源?

Donald Knuth&#xff08;高德纳&#xff09;是一位计算机科学界的著名学者和计算机程序设计的先驱之一。他被誉为计算机科学的“圣经”《计算机程序设计艺术》的作者&#xff0c;提出了著名的“大O符号”来描述算法的时间复杂度和空间复杂度&#xff0c;开发了TeX系统用于排版…

开启数字新时代,5G-Advanced加速带入现实!

在过去的这些年里&#xff0c;我们亲眼见证了5G的崛起。据GSMA&GSA统计&#xff0c;截至2022年12月&#xff0c;全球共部署了超过240张5G商用网络&#xff0c;5G用户超过10亿。在韩国、瑞士、芬兰等地&#xff0c;5G用户渗透率已超过30%。中国的5G网络建设更是独领风骚。截…

形式语言与自动机总结---上下文无关文法(CFG)

第5章上下文无关文法: 设计文法: 做题的时候发现了一个正则表达式到文法的算法 R规则 根据正则式推导右线性文法_右线性文法表达ab*_Pluto 的博客-CSDN博客 举例 设计文法的关键在于理解递归性,文法是一个迭代器 1.The set {| i ≠ j or j ≠ k}, that is, the set of st…

AIGC时代,分享11款超实用AI生成内容检测工具

前往未来百科查看全部AI内容检测工具箱 一、AI 内容检测器 在数字内容创作的世界中&#xff0c;高质量的内容对至关重要。但随着创建的内容量不断增加&#xff0c;确保内容是原创的、高质量的非常具有挑战性。 AI 内容检测器指的是一种利用人工智能技术来自动化审核和识别不当…

进程优先级

目录&#xff1a; 1.进程优先级的概念 2.查看进程优先级的方案 3.linux当中进程的优先级共有40个级别 4.对于进程的其它概念 ---------------------------------------------------------------------------------------------------------------------- 1.进程优先级的概念 为…