家人们谁懂啊!做后端开发真的怕踩接口安全的坑
前几天同事的项目刚上线,就被人抓包篡改了订单金额,从199改成1块钱,直接亏麻了!
后台全是小伙伴私信:“接口有token还需要加密吗?”“API加密是不是很复杂,新手学不会?”“有没有能直接复制的代码,快速落地?”
今天直接掏心窝子,分享一个 SpringBoot 快速实现 API 加密的方案,无需复杂配置,不用懂高深加密原理,全程实操,所有代码均可直接复制,新手10分钟就能搞定,看完直接套用,再也不怕接口泄露、被篡改!
先划重点:本文用 AES 加密算法(目前最常用、最安全的对称加密,前后端统一密钥,简单易维护),实现请求参数、响应结果双重加密,适配所有 SpringBoot 2.x/3.x 版本,不管是对接前端还是第三方,都能直接用!
必看!为什么接口有token,还要做加密?
许多新手都踩过这个坑:觉得接口加了token校验,就万事大吉了❌
大错特错!token 只能验证“你有没有权限访问接口”,根本防不住抓包、篡改和数据泄露!
给大家看3个真实踩坑案例,看完你就懂了:
- ❌ 登录接口未加密:抓包直接拿到用户名、密码明文,用户信息瞬间泄露;
- ❌ 支付接口未加密:请求参数被篡改,订单金额从100改成1,直接造成经济损失;
- ❌ 第三方对接接口未加密:数据被拦截,业务逻辑混乱,排查几天都找不到问题。
而 API 加密能做到:就算被抓包,拿到的也是一堆乱码,根本无法解析,从根源上保住接口安全,这才是后端开发的“保命操作”!
前置准备:3分钟搞定,不用额外装复杂依赖
新手最怕的就是“环境搭建难”,放心!这个方案全程零复杂依赖,SpringBoot 自带相关工具,只要满足2个简单条件,就能上手:
✅ 环境要求:SpringBoot 2.x/3.x(本文用3.2演示,2.x 完全兼容,代码不用改)、JDK 8+
✅ 核心依赖:就2个,SpringBoot 自带可省略,新手直接复制粘贴即可(怕漏的话,加上更稳妥)
1. 核心依赖(直接复制到pom.xml)
<!-- AES 加密依赖(SpringBoot 自带,可省略) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Hutool工具类(简化加密代码,新手必加,不用自己写复杂逻辑) -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.25</version>
</dependency>
说明:Hutool 是后端神器,能帮我们省去几十行加密解密代码,新手直接加,不用纠结原理!
2. 加密核心配置(关键一步,复制就生效)
新建一个配置类,定义 AES 加密的密钥、模式、偏移量(这3个参数,前后端必须完全一致,否则解密失败!),直接复制代码,不用改任何东西:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
/**
* API 加密配置类,直接复制,不用改
* 前后端密钥、模式、偏移量必须一致,否则解密失败
*/
@Configuration
public class ApiEncryptionConfig {
// 加密密钥(32位字符串,安全性最高,直接用,不用改)
// 注意:实际开发中,密钥别硬编码,放配置文件里更安全
private static final String AES_KEY = "1234567890abcdef1234567890abcdef";
// 加密模式(默认即可,前后端一致)
private static final String AES_MODE = "AES/CBC/PKCS5Padding";
// 偏移量(16位字符串,固定这个,不用改)
private static final String AES_IV = "1234567890abcdef";
// 注入AES加密工具,全局可用,不用自己创建
@Bean
public AES aes() {
return new AES(SymmetricAlgorithm.AES, AES_KEY.getBytes(), AES_MODE, AES_IV.getBytes());
}
}
⚠️ 新手避坑:密钥必须是16/24/32位,本文给的32位直接用,不用自己瞎编,避免加密失败!
核心实操:请求+响应双重加密(全程复制,不用改)
重点来了!用 SpringBoot 拦截器实现全局加密解密,一次配置,所有接口生效,不用在每个接口单独写加密逻辑,高效又省心,分4步走,每一步都给好现成代码!
第一步:加密解密工具类(直接复制复用)
新建工具类,封装好加密、解密方法,后续拦截器直接调用,不用重复写代码:
import cn.hutool.crypto.symmetric.AES;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
/**
* 加密解密工具类,直接复制,不用改
*/
@Component
public class ApiEncryptionUtil {
@Autowired
private AES aes;
// 加密:明文 → 密文(Base64编码,避免乱码)
public String encrypt(String plainText) {
if (!StringUtils.hasText(plainText)) {
return plainText;
}
return aes.encryptBase64(plainText.getBytes());
}
// 解密:密文 → 明文(先解Base64,再解密)
public String decrypt(String cipherText) {
if (!StringUtils.hasText(cipherText)) {
return cipherText;
}
return new String(aes.decryptBase64(cipherText));
}
}
第二步:全局拦截器(实现自动加密解密)
新建拦截器,拦截所有API请求,自动解密请求参数、加密响应结果,不用手动干预,代码直接复制:
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.PrintWriter;
/**
* 全局加密解密拦截器,直接复制
* 自动解密请求,自动加密响应,不用改任何逻辑
*/
@Component
public class ApiEncryptionInterceptor implements HandlerInterceptor {
@Autowired
private ApiEncryptionUtil encryptionUtil;
// 请求拦截:解密请求参数(前端传密文,后端解明文)
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 读取前端传的加密请求体
BufferedReader reader = request.getReader();
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
// 解密请求体,放回请求中,供接口使用
String plainText = encryptionUtil.decrypt(sb.toString());
request.setAttribute("requestBody", plainText);
return true;
}
// 响应拦截:加密响应结果(接口返明文,后端加密成密文)
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 获取接口返回的明文结果
String plainText = (String) request.getAttribute("responseBody");
// 加密后返回给前端
String cipherText = encryptionUtil.encrypt(plainText);
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
out.write(cipherText);
out.flush();
out.close();
}
}
⚠️ 重点提醒:SpringBoot 2.x 用 javax.servlet 包,3.x 用 jakarta.servlet 包,2.x 版本只需把 import jakarta… 改成 import javax… 即可,其余代码不变!
第三步:注册拦截器(使其生效,必做!)
新建配置类,注册拦截器,指定需要加密的接口路径,灵活调整,代码直接复制:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 拦截器注册配置,直接复制
* 可灵活调整需要加密的接口、排除不需要加密的接口
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private ApiEncryptionInterceptor apiEncryptionInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 拦截所有 /api/** 开头的接口(可修改,列如 /user/**、/order/**)
// 排除不需要加密的接口(列如登录、验证码接口,按需添加)
registry.addInterceptor(apiEncryptionInterceptor)
.addPathPatterns("/api/**")
.excludePathPatterns("/api/login", "/api/captcha");
}
}
新手提示:addPathPatterns 改需要加密的接口,excludePathPatterns 加不需要加密的接口,列如登录接口可以不加密,按需调整即可。
第四步:接口适配(不用改接口逻辑,直接用)
最爽的地方来了!拦截器已经帮我们做好了加密解密,接口本身不用写任何加密逻辑,正常编写即可,示例代码直接复制:
import com.alibaba.fastjson.JSONObject;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 测试接口,直接复制,不用改
* 无需额外写加密逻辑,拦截器自动处理
*/
@RestController
@RequestMapping("/api")
public class TestApiController {
@PostMapping("/test")
public String test(@RequestAttribute("requestBody") String requestBody) {
// 1. 直接获取解密后的请求体(明文,可直接解析)
JSONObject requestJson = JSONObject.parseObject(requestBody);
String username = requestJson.getString("username");
String password = requestJson.getString("password");
// 2. 正常写业务逻辑(和平时一样,不用改)
System.out.println("用户名:" + username);
System.out.println("密码:" + password);
// 3. 构建响应结果(明文,拦截器自动加密)
JSONObject responseJson = new JSONObject();
responseJson.put("code", 200);
responseJson.put("message", "请求成功");
responseJson.put("data", "欢迎 " + username + " 访问");
// 4. 把响应结果放入request,供拦截器加密
request.setAttribute("responseBody", responseJson.toString());
return responseJson.toString();
}
}
总结:接口只需做2件事——用 @RequestAttribute 获取解密后的请求体,把响应结果放入 request,其余全靠拦截器自动搞定,新手也能一次成功!
前端对接说明(给前端小伙伴看,直接复制)
后端加密做好后,前端需要配合加密解密才能正常对接,以 JavaScript 为例,代码直接复制,和后端保持一致即可:
// 前端 AES 加密解密(密钥、偏移量,必须和后端完全一致!)
const AES_KEY = "1234567890abcdef1234567890abcdef"; // 和后端一样
const AES_IV = "1234567890abcdef"; // 和后端一样
// 加密:明文 → 密文(和后端对应)
function encrypt(plainText) {
const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(AES_KEY), Buffer.from(AES_IV));
let encrypted = cipher.update(plainText, 'utf8', 'base64');
encrypted += cipher.final('base64');
return encrypted;
}
// 解密:密文 → 明文(和后端对应)
function decrypt(cipherText) {
const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(AES_KEY), Buffer.from(AES_IV));
let decrypted = decipher.update(cipherText, 'base64', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
// 接口请求示例(直接复制用)
async function requestApi() {
// 1. 构建请求参数(明文)
const requestData = { username: "test", password: "123456" };
// 2. 加密请求参数
const cipherText = encrypt(JSON.stringify(requestData));
// 3. 发送请求(请求体是密文)
const response = await fetch("/api/test", {
method: "POST",
headers: { "Content-Type": "application/json;charset=utf-8" },
body: cipherText
});
// 4. 解密响应结果
const cipherResponse = await response.text();
const plainResponse = decrypt(cipherResponse);
console.log("接口响应(明文):", JSON.parse(plainResponse));
}
新手必看:4个高频坑,提前避开(少走弯路)
许多新手跟着做,还是会报错,实则都是踩了这4个坑,提前记牢,节省半小时排错时间
- ❌ 坑1:密钥位数不对 → 必须是16/24/32位,本文给的32位直接用,别自己瞎编;
- ❌ 坑2:前后端密钥/模式/偏移量不一致 → 后端用本文的配置,前端复制本文的JS代码,完全一致就不会错;
- ❌ 坑3:SpringBoot 2.x 报错 → 把拦截器里的 jakarta.servlet 改成 javax.servlet 即可;
- ❌ 坑4:请求体为空报错 → 工具类已经做了非空判断,检查前端是否传了空请求体。
实际开发优化提议(可选,进阶用)
本文方案适合快速落地,实际开发中,这2个优化提议必定要做,提升安全性(新手先落地,再优化):
- ✅ 密钥不要硬编码:把密钥、偏移量放到 application.yml 或 Nacos 配置中心,避免泄露;
- ✅ 增加签名验证:在加密基础上,加 MD5 签名,防止请求被篡改,进一步提升接口安全等级,避免出现订单金额被篡改的情况。
最后总结
实则 SpringBoot API 加密真的不难,核心就是「AES 加密 + 拦截器全局处理」,不用懂复杂原理,不用写大量代码,所有代码直接复制,10分钟就能落地。
不管你是新手还是老开发,这个方案都能直接套用,完美解决接口泄露、被篡改的问题,再也不用怕上线踩坑!
❤️ 觉得有用的话,记得点赞、转发、关注我,后续分享更多 SpringBoot 实战干货,新手也能轻松上手,高效开发少踩弯路!





