当前位置: 首页 > news >正文

别再裸奔了!给若依前后端分离项目加上AES接口加密(Vue3 + Spring Boot保姆级配置)

若依框架前后端分离项目AES接口加密实战指南

在当今数据安全日益重要的环境下,企业级应用开发中接口传输的安全性已成为不可忽视的一环。许多开发者在使用若依这类优秀框架时,往往只关注功能实现而忽略了数据传输过程中的安全隐患。本文将带您从零开始,为若依前后端分离项目打造一套完整的AES接口加密方案,涵盖Vue3前端到Spring Boot后端的全链路配置。

1. 为什么需要接口加密?

想象一下,当用户登录时,用户名和密码以明文形式在网络中传输;当查询个人隐私数据时,身份证号、手机号等敏感信息直接暴露在请求响应中——这无异于在互联网上"裸奔"。接口加密的核心价值在于:

  • 防止敏感数据泄露:即使请求被拦截,攻击者也无法直接获取有效信息
  • 抵御中间人攻击:加密后的数据难以被篡改或伪造
  • 满足合规要求:许多行业规范明确要求数据传输必须加密

提示:AES(高级加密标准)作为对称加密算法,在性能和安全性之间取得了良好平衡,是接口加密的理想选择。

2. 前端加密配置(Vue3)

2.1 安装与基础配置

首先在Vue3项目中安装crypto-js库:

npm install crypto-js --save # 如遇网络问题可使用 cnpm install crypto-js --save

创建src/utils/aes.js工具类:

import CryptoJS from 'crypto-js' // 生成随机16位AES密钥 export const generateAESKey = () => { const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' return Array(16).fill(0) .map(() => chars.charAt(Math.floor(Math.random() * chars.length))) .join('') } // AES加密 export const encrypt = (data, key) => { const keyBytes = CryptoJS.enc.Utf8.parse(key) const dataBytes = CryptoJS.enc.Utf8.parse( typeof data === 'object' ? JSON.stringify(data) : data ) const encrypted = CryptoJS.AES.encrypt(dataBytes, keyBytes, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 }) return encrypted.toString() } // AES解密 export const decrypt = (ciphertext, key) => { const keyBytes = CryptoJS.enc.Utf8.parse(key) const decrypted = CryptoJS.AES.decrypt(ciphertext, keyBytes, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 }) return CryptoJS.enc.Utf8.stringify(decrypted).toString() }

2.2 请求拦截器改造

修改src/utils/request.js,添加加密逻辑:

import { encrypt, decrypt } from './aes' // 从环境变量获取配置 const AES_KEY = import.meta.env.VITE_APP_AES_KEY const ENCRYPT_ENABLED = import.meta.env.VITE_APP_ENCRYPT_ENABLED === 'true' // 请求拦截器 service.interceptors.request.use(config => { if (ENCRYPT_ENABLED && config.data) { config.data = encrypt(config.data, AES_KEY) config.headers['X-Encrypted'] = 'true' } return config }) // 响应拦截器 service.interceptors.response.use(response => { if (ENCRYPT_ENABLED && response.data && response.headers['content-type']?.includes('application/json')) { try { response.data = JSON.parse(decrypt(response.data, AES_KEY)) } catch (e) { console.error('解密失败:', e) } } return response.data })

3. 后端加密配置(Spring Boot)

3.1 过滤器实现

创建解密过滤器DecryptionFilter

import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; public class DecryptionFilter implements Filter { private final AES aes; private final boolean enabled; private final List<String> excludeUrls; public DecryptionFilter(String key, boolean enabled, List<String> excludeUrls) { this.aes = new AES(key.getBytes()); this.enabled = enabled; this.excludeUrls = excludeUrls; } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; if (!enabled || shouldExclude(httpRequest.getRequestURI())) { chain.doFilter(request, response); return; } // 包装请求和响应 DecryptionRequestWrapper requestWrapper = new DecryptionRequestWrapper(httpRequest, aes); EncryptionResponseWrapper responseWrapper = new EncryptionResponseWrapper((HttpServletResponse) response); chain.doFilter(requestWrapper, responseWrapper); // 加密响应 if (responseWrapper.getContentType() != null && responseWrapper.getContentType().contains("application/json")) { String encrypted = aes.encryptBase64(responseWrapper.getContent()); response.getWriter().write(encrypted); } } private boolean shouldExclude(String uri) { return excludeUrls.stream().anyMatch(uri::startsWith); } }

3.2 请求/响应包装器

实现请求包装器DecryptionRequestWrapper

public class DecryptionRequestWrapper extends HttpServletRequestWrapper { private final String decryptedBody; public DecryptionRequestWrapper(HttpServletRequest request, AES aes) throws IOException { super(request); String encrypted = IOUtils.toString(request.getReader()); this.decryptedBody = encrypted.isEmpty() ? "" : aes.decryptStr(encrypted); } @Override public BufferedReader getReader() { return new BufferedReader(new StringReader(decryptedBody)); } // 其他需要重写的方法... }

实现响应包装器EncryptionResponseWrapper

public class EncryptionResponseWrapper extends HttpServletResponseWrapper { private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); private PrintWriter writer; public EncryptionResponseWrapper(HttpServletResponse response) { super(response); } @Override public ServletOutputStream getOutputStream() { return new ServletOutputStream() { @Override public void write(int b) { outputStream.write(b); } // 其他必要方法实现... }; } public String getContent() { return outputStream.toString(StandardCharsets.UTF_8); } }

3.3 Spring配置

在配置类中注册过滤器:

@Configuration public class FilterConfig { @Value("${encrypt.enabled:false}") private boolean enabled; @Value("${encrypt.key}") private String key; @Value("${encrypt.exclude-urls:/common/**,/profile/**}") private List<String> excludeUrls; @Bean public FilterRegistrationBean<DecryptionFilter> decryptionFilter() { FilterRegistrationBean<DecryptionFilter> registration = new FilterRegistrationBean<>(); registration.setFilter(new DecryptionFilter(key, enabled, excludeUrls)); registration.addUrlPatterns("/*"); registration.setOrder(Ordered.HIGHEST_PRECEDENCE); return registration; } }

4. 密钥管理与环境配置

4.1 前端环境变量

在项目根目录创建.env文件:

VITE_APP_AES_KEY=Your16ByteAESKey123 VITE_APP_ENCRYPT_ENABLED=true

4.2 后端配置文件

application.yml配置:

encrypt: enabled: true key: Your16ByteAESKey123 exclude-urls: - /common/** - /profile/** - /druid/**

4.3 密钥安全最佳实践

  • 不要硬编码:始终通过环境变量或配置中心管理密钥
  • 区分环境:开发、测试、生产环境使用不同密钥
  • 定期轮换:建立密钥轮换机制,但要注意历史数据解密问题
  • 最小权限:仅对敏感接口启用加密,静态资源等可排除

5. 常见问题排查

5.1 前端常见问题

问题1:加密后后端无法解密

  • 检查前后端密钥是否一致
  • 确认加密模式(ECB/CBC)和填充方式(PKCS7)一致
  • 查看网络请求原始数据,确认传输过程中是否被修改

问题2:性能明显下降

  • 只对必要接口启用加密
  • 考虑使用Web Worker处理加密解密
  • 检查是否重复加密/解密

5.2 后端常见问题

问题1:过滤器不生效

  • 检查过滤器顺序,确保它在安全过滤器之前
  • 确认URL模式配置正确
  • 检查Spring Boot自动配置是否冲突

问题2:解密失败

  • 确认请求Content-Type为application/json
  • 检查是否有其他过滤器修改了请求体
  • 调试查看原始加密字符串是否完整

6. 进阶优化建议

  1. 动态密钥协商:实现密钥定期更换机制,避免长期使用同一密钥
  2. 混合加密方案:结合RSA非对称加密传输AES密钥,提升安全性
  3. 请求签名验证:添加时间戳和签名,防止重放攻击
  4. 性能监控:添加加密解密的耗时统计,及时发现性能瓶颈
  5. 白名单机制:基于用户角色动态决定是否加密

在实际项目中,我们曾遇到一个典型案例:某金融类应用在启用加密后,发现某些安卓设备请求成功率显著下降。经过排查,发现是低端设备加密计算耗时过长导致请求超时。最终通过优化加密策略(仅在WiFi环境下启用强加密)解决了问题。

http://www.jsqmd.com/news/648063/

相关文章:

  • DeepSeek角色扮演指令终极指南:解锁AI自由对话新境界
  • C 语言教程
  • 双系统安装——爽哉爽哉
  • 基于深度学习的苹果叶片病虫害识别系统,resnet50,vgg16,resnet34【pytorch框架,python源码】
  • OpenClaw没凉,只是证明了90%的人并不需要AI Agent
  • AI编程≠Vibe Coding:6种模式一次讲清楚
  • 计算机网络之TCP和UDP的底层机制
  • 生成式AI数据飞轮构建:从0到规模化复利增长的6个关键杠杆(附某金融大模型真实飞轮增速曲线)
  • Flutter 开源鸿蒙动效实战:全场景动效集成精简指南
  • MySQL Filesort
  • 【限时解禁】SITS2026评测套件V1.0完整数据集+评估Pipeline(含中文细粒度标注子集)
  • 快速掌握 FastAPI 路由:从基础到进阶
  • Apache Tomcat 紧急修复多个漏洞
  • ViGEmBus深度解析:Windows内核级游戏控制器虚拟化架构揭秘
  • 5篇2章12节:诊断试验准确性研究与多阈值Meta分析方法(下篇:可视计算)
  • QLabel的四种内容呈现模式
  • Sunshine游戏串流实战解析:构建你的专属高性能云端游戏平台
  • 你怎么知道AI真的做对了?我花了三个月才想明白这个问题
  • 2026年比较好的一次性盘子批量采购厂家推荐 - 行业平台推荐
  • UE5开发必看:5种防止UObject被GC回收的实用技巧(附代码示例)
  • 开源数据大屏AJ-Report:从零搭建到酷炫展示的全流程指南
  • 源码解读:拿下顶会最佳论文的重建式VLA,是如何实现的!
  • iMetaMed | 王诗翔/罗鹏/李剑峰/曾健明—Bizard 平台:加速与提升生物医学数据可视化
  • 叶片泵的结构设计及造型(论文+CAD图纸+三维图+动画仿真……)
  • 嵌入式系统设计实践
  • Leaflet图层顺序实战:如何用setZIndex和bringToFront控制地图元素层级(附常见问题)
  • 有孩家庭接送场景混动车型实证测评:座舱健康与续航便捷性核心指标对比研究
  • 多模态导航应用全栈拆解,从视觉-语音-IMU融合建模到端侧推理压缩实战
  • 终极指南:5分钟快速掌握B站视频转文字开源工具bili2text
  • GLM-4.1V-9B-Base实操手册:如何构造鲁棒提问避免‘无法回答’类失败响应