前言:

在公司协作开发的过程中,自己的项目是公共调用平台,也可以说是中转平台,供公司其他团队的项目进行接口调用。因为是不同团队项目之间的相互调用,所以不能通过openFeign远程调用。只能通过http远程调用,但是在http调用的过程中数据不能通过明文传输,这样是不安全的。所以下面演示如何使用AES秘钥,对接口数据进行加解密。

目录

一,引入maven依赖

二,生成AES对称秘钥

三,将控制台打印的秘钥保存,粘贴到yml文件中去

四,核心加解密工具类

五,封装统一返回对象工具类

5.1,校验重复请求工具类(可选,非必要)

六,接收加密后的数据请求接口(解密示例接口)

七,发送请求加密data业务数据(加密示例接口)

八,发送请求测试

九,升级拓展


一,引入maven依赖

        <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.37</version></dependency>

二,生成AES对称秘钥

运行这一块代码输出秘钥:

@Testpublic void test() {byte[] keyBytes = SecureUtil.generateKey("AES").getEncoded();String keyStr = Base64.encode(keyBytes);   // 转 Base64 字符串,方便存配置System.out.println("AES 密钥:" + keyStr);}

三,将控制台打印的秘钥保存,粘贴到yml文件中去

四,核心加解密工具类

import cn.hutool.core.codec.Base64;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;@Component
public class AesKit {@Value("${aes.key}")private String key;private SymmetricCrypto aes;@PostConstructpublic void init() {this.aes = new SymmetricCrypto(SymmetricAlgorithm.AES, Base64.decode(key));}public String encrypt(String plain) {return aes.encryptBase64(plain);}public String decrypt(String cipher) {return aes.decryptStr(cipher);}
}

五,封装统一返回对象工具类

import com.zqd.common.constant.HttpStatus;
import com.zqd.common.utils.uuid.IdUtils;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.io.Serializable;/*** 加密data业务数据响应实体类*/
@ApiModel(value = "返回对象",description = "返回结果"
)
@Data
public class EncryptionR<T> implements Serializable {private static final long serialVersionUID = 1L;/** 成功 */public static final int SUCCESS = HttpStatus.SUCCESS;/** 失败 */public static final int FAIL = HttpStatus.ERROR;@ApiModelProperty("返回code值")private int code;@ApiModelProperty("时间戳")private Long timestamp=System.currentTimeMillis();@ApiModelProperty("随机数")//如果生成uuid工具类用不了那就切换成你自己生成uuid的工具类private String nonce= IdUtils.fastSimpleUUID();@ApiModelProperty("返回提示信息")private String msg;@ApiModelProperty("返回数据")private T data;public static <T> EncryptionR<T> ok(){return restResult(null, SUCCESS, "操作成功");}public static <T> EncryptionR<T> ok(T data){return restResult(data, SUCCESS, "操作成功");}public static <T> EncryptionR<T> ok(T data, String msg){return restResult(data, SUCCESS, msg);}public static <T> EncryptionR<T> fail(){return restResult(null, FAIL, "操作失败");}public static <T> EncryptionR<T> fail(String msg){return restResult(null, FAIL, msg);}public static <T> EncryptionR<T> fail(T data){return restResult(data, FAIL, "操作失败");}public static <T> EncryptionR<T> fail(T data, String msg){return restResult(data, FAIL, msg);}public static <T> EncryptionR<T> fail(int code, String msg){return restResult(null, code, msg);}private static <T> EncryptionR<T> restResult(T data, int code, String msg){EncryptionR<T> apiResult = new EncryptionR<>();apiResult.setCode(code);apiResult.setData(data);apiResult.setMsg(msg);return apiResult;}
}
5.1,校验重复请求工具类(可选,非必要)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;import java.time.Duration;@Component
public class HttpRequestCheck {@Autowiredpublic RedisTemplate redisTemplate;/*** 校验重复请求* @param timestamp 时间戳* @param nonce 随机数* @return*/public  void isRepeatSubmit(Long timestamp, String nonce) {long now  = System.currentTimeMillis();long diff = Math.abs(now - timestamp);// 允许 60 秒误差(发送请求到接收到请求的时间差)if (diff > 60000) {throw new RuntimeException("请求已过期");}// 防止重复 nonce:Redis 查重String key = "nonce:" + nonce;if (Boolean.TRUE.equals(redisTemplate.hasKey(key))) {throw new RuntimeException("重复请求");}redisTemplate.opsForValue().set(key, "1", Duration.ofMinutes(5));}
}

六,接收加密后的数据请求接口(解密示例接口)

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.zqd.common.annotation.Anonymous;
import com.zqd.common.constant.HttpStatus;
import com.zqd.common.exception.ServiceException;
import com.zqd.system.serverutils.dome2.AesKit;
import com.zqd.system.serverutils.dome2.EncryptionR;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.Objects;@RestController
@RequestMapping("/domeD")
@Api(tags = "测试D")
public class DomeTestControllerB {private static final Logger log = LoggerFactory.getLogger(DomeTestController.class);@AutowiredAesKit aesKit;//    @Autowired
//    HttpRequestCheck httpRequestCheck;@PostMapping("/testD")@ApiOperation(value = "内测试D")@Anonymouspublic EncryptionR queryIncompleteExamination(@RequestBody @Validated String cipher) {EncryptionR req = JSONUtil.toBean(cipher, EncryptionR.class);if(!Objects.equals(HttpStatus.SUCCESS, req.getCode())){throw new ServiceException("请求失败:"+req.getMsg());}//校验重复请求(可选)
//        httpRequestCheck.isRepeatSubmit(req.getTimestamp(), req.getNonce());log.info("接收到的密文:{}", req.getData());String plain = aesKit.decrypt(req.getData().toString());log.info("解密后的明文:{}", JSON.toJSONString(plain));String resp = JSONUtil.toJsonStr("哈哈哈111111111111返回");// 直接返回其他密文字符串return EncryptionR.ok(aesKit.encrypt(resp));}}

七,发送请求加密data业务数据(加密示例接口)

import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.zqd.common.annotation.Anonymous;
import com.zqd.common.constant.HttpStatus;
import com.zqd.common.exception.ServiceException;
import com.zqd.system.serverutils.dome.dome.AesKit;
import com.zqd.system.serverutils.dome.dome.EncryptionR;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.Objects;@RestController
@RequestMapping("/domeE")
@Api(tags = "测试E")
public class DomeTestControllerA {@AutowiredAesKit aesKit;@PostMapping("/testE")@ApiOperation(value = "内测试E")@Anonymouspublic EncryptionR<String> queryIncompleteExamination() {// 1. 构造业务 JSONString json = JSONUtil.toJsonStr("哈哈哈哈");// 2. 加密String cipher = aesKit.encrypt(json);// 3. 发 HTTP,直接发字符串String respCipher = HttpRequest.post("http://localhost:****/game/domeD/testD")//请求地址换成你自己的目标地址url.body(JSON.toJSONString(EncryptionR.ok(cipher))).execute().body();EncryptionR bean = JSONUtil.toBean(respCipher, EncryptionR.class);if(!Objects.equals(HttpStatus.SUCCESS, bean.getCode())){throw new ServiceException("请求失败:"+bean.getMsg());}// 4. 解密 B 的返回String plainResp = aesKit.decrypt(bean.getData().toString());return EncryptionR.ok(plainResp);}}

八,发送请求测试

在DomeTestControllerA中加密业务数据发送请求到DomeTestControllerB解密数据。

DomeTestControllerA:

DomeTestControllerB:

后面DomeTestControllerB响应的业务数据也需要加密响应给DomeTestControllerA,DomeTestControllerA以相同的方式解密即可。

到此就可以实现接口数据的加解密过程了。

九,升级拓展

如果你想实现校验重复请求,打开这行代码即可。

如果觉得粒度不够,没有细粒度到用户id。那么你也可以在我的代码基础上修改。

修改步骤:

1,在HttpRequestCheck中添加属性userId

2,在HttpRequestCheck重载一个isRepeatSubmit方法,入参添加一个用户id。redsi缓存的key在随机数前面加上用户id即可

3,根据你的业务需求调用校验方法

到此结束!!!

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

推荐5个网页模板资源网

1. 企业模板官方网站&#xff1a; http://www.qimoban.com介绍&#xff1a;企业模板(qimoban.com )是一个专注于提供丰富多样的企业模板的优质平台&#xff0c;致力于为企业和个人打造高效、专业、个性化的模板获取渠道。该平台提供海量的企业模板资源&#xff0c;涵盖企业官网…

Redis持久化机制(RDB AOF)

1. RDB RDB 持久化是把当前进程数据生成快照保存到硬盘的过程&#xff0c;触发 RDB 持久化过程分为手动触发和 自动触发&#xff0c;存储的是二进制数据。 1.1 手动触发 使用 save 和 bgsave 命令触发&#xff1a; save&#xff1a;Redis服务主进程阻塞式执行持久化操作&…

【css】让浏览器支持小于12px的文字

【css】让浏览器支持小于12px的文字.demo {display: inline-block;/** 使用Webkit引擎的变换属性&#xff08;主要针对旧版Safari/Chrome&#xff09; **/-webkit-transform: scale(0.8); }注意&#xff1a;display: inline-block; 一定要加上&#xff01;1.transform: scale(…

机器学习-基础入门:从概念到核心方法论

在人工智能飞速发展的今天&#xff0c;机器学习作为其核心技术&#xff0c;正深刻改变着我们的生活与工作。从 AlphaGo 战胜围棋世界冠军&#xff0c;到日常的智能推荐、人脸识别&#xff0c;机器学习的应用无处不在。本文将从基础概念出发&#xff0c;带你系统了解机器学习的核…

《Leetcode》-面试题-hot100-动态规划

题目列表 70. 爬楼梯 简单难度 leetcode链接 118. 杨辉三角 简单难度 leetcode链接 198. 打家劫舍 中等难度 leetcode链接 279.完全平方数 中等难度 leetcode链接 322.零钱兑换 中等难度 leetcode链接 139.单词拆分 中等难度 leetcode链接 300.最长递增子序列 中等难度 l…

数巅中标中建科技AI知识库项目,开启建筑业数智化新篇章

AI正以前所未有的迅猛态势渗透进建筑业的每一处脉络。在这场数智化转型浪潮中&#xff0c;AI技术如何与建筑业基因深度融合&#xff1f;如何充分释放数据价值&#xff1f;近日&#xff0c;数巅成功中标中建科技集团有限公司“企业AI知识库研发”项目&#xff0c;这一“大语言模…

想要PDF翻译保留格式?用对工具是关键

嘿&#xff0c;朋友&#xff01;最近有没有被PDF翻译的事儿搞得焦头烂额呀&#xff1f;尤其是碰到韩文PDF文件的时候&#xff0c;是不是更头疼了&#xff1f;别担心&#xff0c;我最近也遇到了类似的问题&#xff0c;试了不少软件&#xff0c;发现有五款软件在处理韩文PDF翻译时…

【MySQL✨】服务器安装 MySQL 及配置相关操作

1. 安装 MySQL 在安装 MySQL 时&#xff0c;如果使用官方 RPM 源&#xff0c;会遇到 GPG 密钥验证失败的错误&#xff0c;可以按照以下步骤解决&#xff1a; 解决 GPG 密钥验证失败的问题下载 MySQL 官方 GPG 密钥 使用以下命令下载并安装 MySQL 的官方 GPG 密钥&#xff1a; w…

大数据量返回方案(非分页)

一、普通方式返回100万条数据RestController RequestMapping("/bad") public class BadController {Autowiredprivate UserRepository userRepository;/*** 危险&#xff01;一次性加载 100 万条到内存*/GetMapping("/all-users")public List<User> …

基于Casbin的微服务细粒度权限控制方案对比与实践

基于Casbin的微服务细粒度权限控制方案对比与实践 随着微服务架构在互联网和企业级应用中的广泛应用&#xff0c;服务间的安全边界愈发重要。传统的集中式权限控制方式已难以满足微服务的高并发、动态扩展和多语言支持等需求。本文将从主流的三种微服务权限控制方案入手&#x…

5G毫米波现状概述(截止2025 年7月)

5G毫米波现状概述(截止2025 年7月&#xff09; 原创 modem协议笔记 2025年07月25日 06:01 广东 听全文 当你在体育馆看球赛时&#xff0c;想发段实时视频到朋友圈却总卡成PPT&#xff1b;当郊区的父母抱怨“光纤拉不到家&#xff0c;网速比蜗牛慢”—这些场景背后&#xff…

thymeleaf 日期格式化显示

在Thymeleaf中处理日期格式化显示主要有以下几种方式&#xff1a; 1. 使用#dates.format()方法进行基础格式化&#xff1a; <p th:text"${#dates.format(dateObj, yyyy-MM-dd HH:mm:ss)}"></p>这种方法支持自定义格式模式&#xff0c;如yyyy表示年份、MM…

【经验分享】如何在Vscode的Jupyter Notebook中设置默认显示行号

【经验分享】如何在Vscode的Jupyter Notebook中设置默认显示行号 打开设置&#xff0c;搜索&#xff1a;Notebook: Line Number&#xff0c;然后把这个设置为on

蓝桥杯STL stack

STL stack 概述栈&#xff08;stack&#xff09;是一种遵循**后进先出&#xff08;LIFO&#xff09;**原则的线性数据结构&#xff0c;仅允许在栈顶进行插入和删除操作。STL&#xff08;Standard Template Library&#xff09;中的 stack 是一个容器适配器&#xff0c;基于其他…

从0到1:飞算JavaAI如何用AI魔法重构MCP服务全生命周期?

摘要 本文详细介绍了如何利用飞算JavaAI技术实现MCP&#xff08;Model Context Protocol&#xff09;服务的创建及通过的全过程。首先阐述了飞算JavaAI的基本概念、特点和优势&#xff0c;接着对MCP服务的需求进行分析&#xff0c;然后按照软件开发流程&#xff0c;从系统设计、…

Webpack Loader 完全指南:从原理到配置的深度解析

掌握 Webpack Loader 的核心机制&#xff0c;解锁前端工程化进阶技能前言&#xff1a;为什么需要理解 Loader&#xff1f; 在现代前端工程化体系中&#xff0c;Webpack 已成为构建工具的事实标准。然而面对非标准 JavaScript 文件或自定义语法时&#xff0c;你是否遇到过 Modul…

读书笔记:《我看见的世界》

《我看见的世界.李飞飞自传》李飞飞 著&#xff0c;赵灿 译个人理解&#xff1a; 是本自传&#xff0c;也是AI的发展史 坚持&#xff0c;总会转机&#xff0c;“一不小心”也许就成了算法、大规模数据、原始算力人工智能似乎一夜之间从一个小众的学术领域爆发成为推动全球变革的…

使用纯NumPy实现回归任务:深入理解机器学习本质

在深度学习框架普及的今天&#xff0c;回归基础用NumPy从头实现机器学习模型具有特殊意义。本文将完整演示如何用纯NumPy实现二次函数回归任务&#xff0c;揭示机器学习底层原理。整个过程不使用任何深度学习框架&#xff0c;每一行代码都透明可见。1. 环境配置与数据生成 impo…

java理解

springboot 打包 mvn install:install-file -Dfile=<path-to-jar> -DgroupId=<group-id> -DartifactId=<artifact-id> -Dversion=<version> -Dpackaging=jar <path-to-jar> 是你的 JAR 文件的路径。 <group-id> 是你的项目的组 ID。 <…

图论核心算法详解:从存储结构到最短路径(附C++实现)

目录 一、图的基础概念与术语 二、图的存储结构 1. 邻接矩阵 实现思路&#xff1a; 2. 邻接表 实现思路&#xff1a; 应用场景&#xff1a; 时间复杂度分析&#xff1a; 三、图的遍历算法 1. 广度优先搜索&#xff08;BFS&#xff09; 核心思想&#xff1a; 应用场…