这是一个或许对你有用的社群 一对一交流/面试小册/简历优化/求职解惑欢迎加入「芋道快速开发平台」知识星球。下面是星球提供的部分资料《项目实战视频》从书中学往事上“练”《互联网高频面试题》面朝简历学习春暖花开《架构 x 系统设计》摧枯拉朽掌控面试高频场景题《精进 Java 学习指南》系统学习互联网主流技术栈《必读 Java 源码专栏》知其然知其所以然这是一个或许对你有用的开源项目国产Star破10w的开源项目前端包括管理后台、微信小程序后端支持单体、微服务架构RBAC权限、数据权限、SaaS多租户、商城、支付、工作流、大屏报表、ERP、CRM、AI大模型、IoT物联网等功能多模块https://gitee.com/zhijiantianya/ruoyi-vue-pro微服务https://gitee.com/zhijiantianya/yudao-cloud视频教程https://doc.iocoder.cn【国内首批】支持 JDK17/21SpringBoot3、JDK8/11Spring Boot2双版本一、架构设计核心设计理念二、代码实现2.1 加解密注解定义2.2 加解密配置类2.3 加解密处理器接口2.4 AES算法处理器实现类2.5 请求体解密Advice2.6 响应体加密Advice2.7 自动配置类2.8 配置文件示例三、验证测试3.1 测试接口定义3.2 测试Service实现3.3 单元测试3.4 测试结果验证四、前后端联调4.1 前端加解密工具类4.2 axios请求封装4.3 测试接口调用4.4 Vue3页面测试4.5 联调结果验证总结一、架构设计核心设计理念本文将详细讲解一套注解驱动的SpringBoot接口加解密方案该方案具备高扩展性、可配置性核心设计包含四大维度注解驱动- 通过自定义Crypto注解标记需要加解密的接口精准控制接口加解密范围。配置中心- 支持动态开关加解密功能同时可灵活选择加密算法适配不同业务场景。算法扩展- 采用接口化设计封装加密算法支持算法模块的可插拔替换无需改动核心代码。消息处理- 基于Spring的Advice机制拦截请求/响应无侵入式完成加解密处理。基于 Spring Boot MyBatis Plus Vue Element 实现的后台管理系统 用户小程序支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能项目地址https://github.com/YunaiV/ruoyi-vue-pro视频教程https://doc.iocoder.cn/video/二、代码实现2.1 加解密注解定义首先定义核心注解Crypto用于标记需要加解密的接口可分别控制请求/响应的加解密开关import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 接口加解密注解 * 标记在Controller的方法上控制该接口的请求/响应加解密行为 */ Target(ElementType.METHOD) // 注解仅作用于方法 Retention(RetentionPolicy.RUNTIME) // 运行时保留便于AOP拦截获取 publicinterface Crypto { /** * 是否对响应体加密默认开启 */ boolean response() default true; /** * 是否对请求体解密默认开启 */ boolean request() default true; }2.2 加解密配置类封装加解密相关配置项通过配置文件注入支持动态调整import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; /** * 加解密配置属性类 * 读取配置文件中crypto前缀的配置项 */ Data// Lombok注解自动生成get/set方法 ConfigurationProperties(prefix crypto) // 绑定配置文件中crypto前缀的配置 publicclass CryptoProperties { /** * 加解密功能总开关默认关闭 */ privateboolean enabled false; /** * 加密算法类型默认AES */ private String algorithm aes; /** * AES算法密钥BASE64格式 */ private String aesKey; }2.3 加解密处理器接口为保证算法的可扩展性定义统一的加解密处理器接口所有加密算法需实现该接口import cn.hutool.crypto.CryptoException; /** * 加解密处理器接口 * 定义加解密的标准方法所有加密算法实现类需遵循此规范 */ public interface CryptoProcessor { /** * 加密方法 * param content 待加密的明文内容 * return 加密后的密文 * throws CryptoException 加密异常 */ String encrypt(String content) throws CryptoException; /** * 解密方法 * param content 待解密的密文内容 * return 解密后的明文 * throws CryptoException 解密异常 */ String decrypt(String content) throws CryptoException; }2.4 AES算法处理器实现类基于AES/CBC/PKCS5Padding模式实现具体的加解密逻辑是上述接口的核心实现import cn.hutool.crypto.CryptoException; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Base64; /** * AES加解密处理器实现类 * 采用CBC模式PKCS5Padding填充方式IV向量取自密钥前16字节 */ publicclass AESCryptoProcessor implements CryptoProcessor { // AES算法模式AES/CBC/PKCS5Padding privatestaticfinal String ALGORITHM AES/CBC/PKCS5Padding; // AES密钥对象 privatefinal SecretKey secretKey; // 初始化向量IV privatefinal IvParameterSpec iv; /** * 构造方法初始化密钥和IV向量 * param base64Key BASE64编码的AES密钥16/24/32字节 */ public AESCryptoProcessor(String base64Key) { // 解码BASE64格式的密钥 byte[] keyBytes Base64.getDecoder().decode(base64Key); // 创建AES密钥对象 this.secretKey new SecretKeySpec(keyBytes, AES); // 取密钥前16字节作为IV向量CBC模式必须指定IV this.iv new IvParameterSpec(Arrays.copyOfRange(keyBytes, 0, 16)); } /** * AES加密实现 * param content 待加密的明文 * return BASE64编码的密文 * throws CryptoException 加密失败异常 */ Override public String encrypt(String content) { try { // 创建Cipher对象指定算法模式 Cipher cipher Cipher.getInstance(ALGORITHM); // 初始化加密模式 cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv); // 执行加密并编码为BASE64字符串 byte[] encrypted cipher.doFinal(content.getBytes(StandardCharsets.UTF_8)); return Base64.getEncoder().encodeToString(encrypted); } catch (Exception e) { thrownew CryptoException(AES加密失败, e); } } /** * AES解密实现 * param content BASE64编码的密文 * return 解密后的明文 * throws CryptoException 解密失败异常 */ Override public String decrypt(String content) { try { // 创建Cipher对象指定算法模式 Cipher cipher Cipher.getInstance(ALGORITHM); // 初始化解密模式 cipher.init(Cipher.DECRYPT_MODE, secretKey, iv); // 解码BASE64密文并执行解密 byte[] decoded Base64.getDecoder().decode(content); byte[] decrypted cipher.doFinal(decoded); // 转换为UTF-8编码的明文 returnnew String(decrypted, StandardCharsets.UTF_8); } catch (Exception e) { thrownew CryptoException(AES解密失败, e); } } }2.5 请求体解密Advice基于Spring的RequestBodyAdvice拦截请求对标记Crypto的接口请求体进行解密处理import cn.hutool.crypto.CryptoException; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.type.TypeFactory; import org.springframework.core.MethodParameter; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpInputMessage; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.util.StreamUtils; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Type; import java.nio.charset.StandardCharsets; import java.util.Objects; /** * 请求体解密Advice * 拦截POST/PUT等带请求体的请求对标记Crypto的接口解密请求体 */ ControllerAdvice// 全局控制器增强 publicclass CryptoRequestBodyAdvice implements RequestBodyAdvice { // 加解密处理器 privatefinal CryptoProcessor cryptoProcessor; // 加解密配置 privatefinal CryptoProperties properties; // JSON解析器 privatefinal ObjectMapper objectMapper new ObjectMapper(); /** * 构造注入依赖 * param cryptoProcessor 加解密处理器 * param properties 加解密配置 */ public CryptoRequestBodyAdvice(CryptoProcessor cryptoProcessor, CryptoProperties properties) { this.cryptoProcessor cryptoProcessor; this.properties properties; } /** * 判断是否需要处理当前请求 * param parameter 方法参数 * param targetType 目标类型 * param converterType 消息转换器类型 * return true需要处理false跳过 */ Override public boolean supports(MethodParameter parameter, Type targetType, Class? extends HttpMessageConverter? converterType) { // 条件配置开启 方法有Crypto注解 注解开启request解密 return properties.isEnabled() parameter.hasMethodAnnotation(Crypto.class) Objects.requireNonNull(parameter.getMethodAnnotation(Crypto.class)).request(); } /** * 读取请求体前解密处理 * param inputMessage 原始请求消息 * param parameter 方法参数 * param targetType 目标类型 * param converterType 消息转换器类型 * return 解密后的请求消息 * throws IOException IO异常 */ Override public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class? extends HttpMessageConverter? converterType) throws IOException { if (properties.isEnabled()) { // 读取原始加密请求体 String encrypted StreamUtils.copyToString(inputMessage.getBody(), StandardCharsets.UTF_8); // 移除可能的首尾引号前端传参可能带引号 encrypted encrypted.replaceAll(^\|\$, ); // 解密请求体 String decrypted cryptoProcessor.decrypt(encrypted); // 验证解密后的数据格式是否合法JSON validateDecryptedData(decrypted, targetType); // 返回解密后的请求体 returnnew ByteArrayHttpInputMessage( decrypted.getBytes(StandardCharsets.UTF_8), inputMessage.getHeaders() ); } return inputMessage; } /** * 验证解密后的数据是否符合目标类型的JSON格式 * param decrypted 解密后的字符串 * param targetType 目标类型 * throws CryptoException 数据格式异常 */ private void validateDecryptedData(String decrypted, Type targetType) { try { // 尝试解析JSON验证格式合法性 new ObjectMapper().readValue(decrypted, constructJavaType(targetType)); } catch (IOException e) { thrownew CryptoException(解密数据格式无效: e.getMessage(), e); } } /** * 构建JavaType对象适配泛型 * param targetType 目标类型 * return JavaType */ private JavaType constructJavaType(Type targetType) { return TypeFactory.defaultInstance().constructType(targetType); } /** * 自定义HttpInputMessage实现类 * 用于封装解密后的请求体字节数组 */ publicstaticclass ByteArrayHttpInputMessage implements HttpInputMessage { // 解密后的请求体字节数组 privatefinalbyte[] body; // 请求头 privatefinal HttpHeaders headers; public ByteArrayHttpInputMessage(byte[] body, HttpHeaders headers) { this.body body; this.headers new HttpHeaders(); this.headers.putAll(headers); // 更新Content-Length为解密后的长度 this.headers.setContentLength(body.length); } Override public InputStream getBody() throws IOException { // 返回字节数组输入流 returnnew ByteArrayInputStream(body); } Override public HttpHeaders getHeaders() { return headers; } } /** * 读取请求体后处理此处无需额外处理 */ Override public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class? extends HttpMessageConverter? converterType) { return body; } /** * 空请求体处理此处无需额外处理 */ Override public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class? extends HttpMessageConverter? converterType) { return body; } /** * 解析解密后的数据备用方法 * param decrypted 解密后的字符串 * param targetType 目标类型 * return 解析后的对象 * throws JsonProcessingException JSON解析异常 */ private Object parseDecryptedData(String decrypted, Type targetType) throws JsonProcessingException { return objectMapper.readValue(decrypted, objectMapper.constructType(targetType)); } }2.6 响应体加密Advice基于Spring的ResponseBodyAdvice拦截响应对标记Crypto的接口响应体进行加密处理import cn.hutool.crypto.CryptoException; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.core.MethodParameter; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; import java.util.Objects; /** * 响应体加密Advice * 拦截控制器响应对标记Crypto的接口加密响应体 */ ControllerAdvice// 全局控制器增强 publicclass CryptoResponseBodyAdvice implements ResponseBodyAdviceObject { // 加解密处理器 privatefinal CryptoProcessor cryptoProcessor; // 加解密配置 privatefinal CryptoProperties properties; // JSON解析器 privatefinal ObjectMapper objectMapper new ObjectMapper(); /** * 构造注入依赖 * param cryptoProcessor 加解密处理器 * param properties 加解密配置 */ public CryptoResponseBodyAdvice(CryptoProcessor cryptoProcessor, CryptoProperties properties) { this.cryptoProcessor cryptoProcessor; this.properties properties; } /** * 判断是否需要处理当前响应 * param returnType 返回值类型 * param converterType 消息转换器类型 * return true需要处理false跳过 */ Override public boolean supports(MethodParameter returnType, Class? extends HttpMessageConverter? converterType) { // 条件配置开启 (方法有Crypto注解且开启response加密 或 异常响应) return (properties.isEnabled() ((returnType.hasMethodAnnotation(Crypto.class) Objects.requireNonNull(returnType.getMethodAnnotation(Crypto.class)).response())) || isExceptionResponse(returnType) ); } /** * 判断是否为异常响应 * param returnType 返回值类型 * return true异常响应false正常响应 */ private boolean isExceptionResponse(MethodParameter returnType) { // 异常处理类通常标记ResponseBody return Objects.requireNonNull(returnType.getMethod()).getDeclaringClass() .isAnnotationPresent(ResponseBody.class); } /** * 返回响应体前加密处理 * param body 原始响应体 * param returnType 返回值类型 * param selectedContentType 响应媒体类型 * param selectedConverterType 消息转换器类型 * param request 服务端请求 * param response 服务端响应 * return 加密后的响应体 */ Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class? extends HttpMessageConverter? selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { try { // 仅对自定义Result类型的响应加密适配业务统一返回格式 if (body instanceof Result result properties.isEnabled()) { // 添加响应头标记响应已加密 response.getHeaders().add(x-encrypt-response, AES); response.getHeaders().add(x-encrypt-error, AES); // 将响应体转为JSON字符串 String rawData objectMapper.writeValueAsString(result); // 加密并返回密文 return cryptoProcessor.encrypt(rawData); } } catch (Exception e) { thrownew CryptoException(异常响应加密失败, e); } // 非Result类型直接返回原始数据 return body; } }2.7 自动配置类基于SpringBoot自动配置机制初始化加解密相关Bean降低接入成本import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * 加解密自动配置类 * 自动初始化加解密相关Bean无需手动配置 */ Configuration// 配置类 ConditionalOnWebApplication// 仅在Web环境下生效 EnableConfigurationProperties(CryptoProperties.class) // 启用配置属性绑定 public class CryptoAutoConfiguration { /** * 初始化加解密处理器Bean * 根据配置的算法类型创建对应实现类 * param properties 加解密配置 * return 加解密处理器 */ Bean ConditionalOnMissingBean// 不存在时才创建支持自定义覆盖 public CryptoProcessor cryptoProcessor(CryptoProperties properties) { if (aes.equalsIgnoreCase(properties.getAlgorithm())) { // 校验AES密钥是否配置 if (properties.getAesKey() null || properties.getAesKey().isEmpty()) { thrownew IllegalArgumentException(AES密钥未配置请设置crypto.aes-key); } returnnew AESCryptoProcessor(properties.getAesKey()); } // 暂不支持其他算法可扩展 thrownew UnsupportedOperationException(不支持的加密算法: properties.getAlgorithm()); } /** * 初始化请求体解密Advice Bean * param processor 加解密处理器 * param properties 加解密配置 * return 请求体解密Advice */ Bean public CryptoRequestBodyAdvice cryptoRequestBodyAdvice(CryptoProcessor processor, CryptoProperties properties) { returnnew CryptoRequestBodyAdvice(processor, properties); } /** * 初始化响应体加密Advice Bean * param processor 加解密处理器 * param properties 加解密配置 * return 响应体加密Advice */ Bean public CryptoResponseBodyAdvice cryptoResponseBodyAdvice(CryptoProcessor processor, CryptoProperties properties) { returnnew CryptoResponseBodyAdvice(processor, properties); } }2.8 配置文件示例在application.yml中配置加解密相关参数支持动态调整 基于SpringCloudAlibabaGatewayNacosRocketMQVueElement实现的后台管理系统用户小程序支持RBAC动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能 * 项目地址https://github.com/YunaiV/yudao-cloud * 视频教程https://doc.iocoder.cn/video/ # 加解密配置 crypto: enabled:true# 是否开启加解密功能true开启false关闭 algorithm:aes# 加密算法类型当前仅支持aes aes-key:MTIzNDU2Nzg5MDEyMzQ1Ng# BASE64格式的AES密钥16字节128位示例密钥仅用于测试生产需替换为安全密钥三、验证测试3.1 测试接口定义编写用户登录接口标记Crypto注解启用加解密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; /** * 用户控制器 * 测试加解密功能的示例接口 */ RestController RequestMapping(/api/auth/admin) publicclass UserController { privatefinal IUserService userService; // 构造注入UserService public UserController(IUserService userService) { this.userService userService; } /** * 登录接口 * Crypto注解开启请求解密和响应加密 * param userInfo 登录参数自动解密 * return 登录结果自动加密 */ PostMapping(/login) Crypto// 标记接口需要加解密 public ResultString login(RequestBody UserDto userInfo) { String token userService.login(userInfo); return Result.ok(登录成功, token); } }3.2 测试Service实现编写登录业务逻辑模拟用户名密码校验import cn.dev33.satoken.stp.StpUtil; import org.springframework.stereotype.Service; /** * 用户服务实现类 * 模拟登录业务逻辑 */ Service publicclass UserServiceImpl implements IUserService { /** * 登录业务逻辑 * param userInfo 登录参数 * return 登录令牌 * throws RuntimeException 用户名或密码错误时抛出异常 */ Override public String login(UserDto userInfo) { // 模拟用户名密码校验 if (admin.equals(userInfo.getUsername()) 123456.equals(userInfo.getPassword())) { // 模拟登录生成令牌 StpUtil.login(546); return StpUtil.getTokenValue(); } thrownew RuntimeException(用户名或密码错误); } }3.3 单元测试编写AES算法单元测试验证加解密逻辑正确性import org.junit.jupiter.api.Test; importstatic org.junit.jupiter.api.Assertions.assertEquals; /** * AES加解密处理器单元测试 * 验证加解密逻辑是否正确 */ class AESCryptoProcessorTest { // 测试用BASE64密钥对应原始密钥1234567890123456 privatefinal String testKey MTIzNDU2Nzg5MDEyMzQ1Ng; // 初始化AES处理器 privatefinal AESCryptoProcessor aesCryptoProcessor new AESCryptoProcessor(testKey); // 测试明文 privatefinal String testContent {\n \username\: \admin\,\n \password\: \123456\,\n \role\: \\\n }; /** * 测试加密方法 */ Test void encrypt() { String encrypt aesCryptoProcessor.encrypt(testContent); System.out.println(加密后的密文 encrypt); // 密文非空校验 assert encrypt ! null !encrypt.isEmpty(); } /** * 测试解密方法 * 验证解密后的数据与原明文一致 */ Test void decrypt() { // 先加密生成密文 String encrypt aesCryptoProcessor.encrypt(testContent); // 解密密文 String decrypt aesCryptoProcessor.decrypt(encrypt); System.out.println(解密后的明文 decrypt); // 校验解密结果与原明文一致 assertEquals(testContent.replaceAll(\\s, ), decrypt.replaceAll(\\s, )); } }3.4 测试结果验证1.执行单元测试加密测试明文得到密文w4JeMik62JKILEZAulgav0rFDrJ2HegTk2XxQgMXF4UrmiYPtLg5sd5pwPYqnXrskGhjC0VrFaVR1xFQz3dA2.调用登录接口传入上述密文接口返回加密后的响应6tmr623112r3OFkPes2XetsKcVO/FgDEUD3cT8dxBWC8c8gKMNcqAhxPORuk3W581r0KKbDY/O4iOWX79HQN2hqv/LDMdlTEhJml4zZUd5qtomeU51eaHauujsg5FoGsn7/Hgq2vHze2q5JuQbQUw3.对返回的密文解密得到最终响应结果{code:200,success:true,msg:登录成功,data:xxxx-xxxx-xxxx-xxxx}四、前后端联调4.1 前端加解密工具类封装AES加解密工具类与后端算法保持一致// /src/utils/crypto.js import CryptoJS fromcrypto-js // 加解密配置与后端一致CBC模式PKCS7填充 const CRYPTO_CONFIG { mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 } /** * AES加解密工具 * 与后端AESCryptoProcessor算法完全对齐 */ exportconst aes { /** * AES加密 * param {Object} data 待加密的原始数据 * param {String} key BASE64格式的AES密钥 * returns {String} 加密后的密文 */ encrypt(data, key) { // 解码BASE64密钥 const keyBytes CryptoJS.enc.Base64.parse(key) // 取密钥前16字节作为IV向量与后端一致 const iv CryptoJS.lib.WordArray.create(keyBytes.words.slice(0, 4)) // 执行加密 const encrypted CryptoJS.AES.encrypt( JSON.stringify(data), keyBytes, { ...CRYPTO_CONFIG, iv } ) // 返回BASE64格式密文 return encrypted.toString() }, /** * AES解密 * param {String} ciphertext 加密后的密文 * param {String} key BASE64格式的AES密钥 * returns {Object} 解密后的原始数据 */ decrypt(ciphertext, key) { // 解码BASE64密钥 const keyBytes CryptoJS.enc.Base64.parse(key) // 取密钥前16字节作为IV向量与后端一致 const iv CryptoJS.lib.WordArray.create(keyBytes.words.slice(0, 4)) // 执行解密 const decrypted CryptoJS.AES.decrypt( ciphertext, keyBytes, { ...CRYPTO_CONFIG, iv } ) // 转换为JSON对象返回 returnJSON.parse(decrypted.toString(CryptoJS.enc.Utf8)) } }4.2 axios请求封装封装axios拦截器自动加密请求体、解密响应体// /src/api/request.js import axios fromaxios import { aes } from../utils/crypto import qs fromqs // 创建axios实例 const service axios.create({ baseURL: import.meta.env.VUE_APP_API_BASE_URL, // 接口基础地址 timeout: 10000, // 请求超时时间 paramsSerializer:params qs.stringify(params, { arrayFormat: repeat }) // 参数序列化 }) /** * 请求拦截器 * 对标记crypto:true的请求加密请求体 */ service.interceptors.request.use(config { if (config.crypto) { // 从环境变量获取AES密钥 const key import.meta.env.VITE_VUE_APP_AES_KEY // 加密请求体 config.data aes.encrypt(config.data, key) // 添加请求头标记请求已加密 config.headers[x-encrypt-request] AES // 设置Content-Type为JSON config.headers[Content-Type] application/json } return config },error { // 请求错误处理 returnPromise.reject(error) }) /** * 响应拦截器 * 对标记加密的响应自动解密 */ service.interceptors.response.use(response { // 响应头包含x-encrypt-response说明响应已加密 if (response.headers[x-encrypt-response]) { const key import.meta.env.VITE_VUE_APP_AES_KEY // 解密响应体 response.data aes.decrypt(response.data, key) } return response.data },error { // 异常响应解密如后端返回的加密错误信息 if (error.response?.headers[x-encrypt-error]) { const key import.meta.env.VITE_VUE_APP_AES_KEY const decryptedError aes.decrypt(error.response.data, key) // 替换错误信息为解密后的内容 error.message decryptedError.msg || 请求失败 } console.log(请求失败:, error) returnPromise.reject(error) }) exportdefault service4.3 测试接口调用封装登录接口调用方法启用加解密// /src/api/userInfoRequest.js import request from ./request.js; /** * 登录接口请求 * param {Object} data 登录参数用户名密码 * returns {Promise} 请求Promise */ export function postSecureData(data) { return request({ url: /api/auth/admin/login, method: post, data: data, crypto: true // 启用加解密 }) }4.4 Vue3页面测试编写Vue3页面调用登录接口测试加解密template div classlogin-container a-input v-model:valueuser.username placeholder请输入用户名 stylemargin-bottom: 10px/ a-input v-model:valueuser.password typepassword placeholder请输入密码 stylemargin-bottom: 10px/ a-button typeprimary clicklogin请求接口/a-button /div /template script setup import { postSecureData } from./api/userInfoRequest.js import { reactive } fromvue; import { aes } from./utils/crypto.js import { message } fromant-design-vue; // 响应式用户数据 const user reactive({ username: admin, password: 123456 }) // 登录方法 const login async () { try { console.log(点击成功原始数据, user) // 调用登录接口 const res await postSecureData(user) if (res.code 200 res.success) { message.success(登录成功) console.log(登录成功令牌, res.data) } else { message.error(res.msg) } } catch (error) { message.error(error.message) } } // 测试加解密工具类 const testKey MTIzNDU2Nzg5MDEyMzQ1Ng console.log(前端加密测试, aes.encrypt(user, testKey)) console.log(前端解密测试, aes.decrypt(6tmr623112r3OFkPes2XetsKcVO/FgDEUD3cT8dxBWC8c8gKMNcqAhxPORuk3W52YPDDP0XKLacMp1Jk8h5MUDOsYKzVo6BaH6Y2aUdggJCu5j/q65nMDMXTY5qPWwOFSYGIr4Hz9tm6VEwAXEAQ, testKey)) /script4.5 联调结果验证请求参数加密前端传入的{username: admin, password: 123456}会被自动加密为密文传输响应结果加密后端返回的登录结果会被自动加密前端接收后解密展示异常场景处理用户名/密码错误时后端抛出的异常信息会加密返回前端解密后提示错误。总结本文实现的SpringBoot注解式接口加解密方案具备以下优势无侵入性基于注解和AOP实现无需修改业务代码高扩展性算法接口化设计可快速扩展RSA、SM4等其他算法灵活性支持动态开关、算法配置适配不同环境需求易用性前后端封装工具类联调成本低。该方案可直接应用于需要接口加解密的场景如支付、用户敏感信息传输提升接口安全性。欢迎加入我的知识星球全面提升技术能力。 加入方式“长按”或“扫描”下方二维码噢星球的内容包括项目实战、面试招聘、源码解析、学习路线。文章有帮助的话在看转发吧。 谢谢支持哟 (*^__^*