SpringBoot實(shí)現(xiàn)接口數(shù)據(jù)加解密的三種解決方案
一、為什么需要接口數(shù)據(jù)加解密?
在金融支付、用戶隱私信息傳輸?shù)葓?chǎng)景中,接口數(shù)據(jù)若以明文傳輸,極易被中間人攻擊竊取。例如:
- 用戶登錄時(shí)的密碼、身份證號(hào)等敏感信息
- 企業(yè)間數(shù)據(jù)交互的核心業(yè)務(wù)參數(shù)
- 移動(dòng)端與后臺(tái)交互的 token 憑證
Spring Boot 提供了多種優(yōu)雅的加解密實(shí)現(xiàn)方案,既能保證數(shù)據(jù)安全,又能最小化業(yè)務(wù)侵入性。本文將從原理到實(shí)戰(zhàn),帶你掌握三種主流實(shí)現(xiàn)方式。
二、核心加解密算法選擇
1. 對(duì)稱加密(AES)
優(yōu)勢(shì):加密速度快,適合大流量數(shù)據(jù)傳輸
缺點(diǎn):密鑰需安全存儲(chǔ),適合客戶端與服務(wù)端一對(duì)一場(chǎng)景
// AES 工具類(128位密鑰)
public class AESUtils {
private static final String KEY = "your_16bit_secret_key";
private static final String ALGORITHM = "AES/ECB/PKCS5Padding";
public static String encrypt(String data) throws Exception {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(KEY.getBytes(), "AES"));
return Base64.getEncoder().encodeToString(cipher.doFinal(data.getBytes()));
}
public static String decrypt(String data) throws Exception {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(KEY.getBytes(), "AES"));
return new String(cipher.doFinal(Base64.getDecoder().decode(data)));
}
}
2. 非對(duì)稱加密(RSA)
優(yōu)勢(shì):密鑰對(duì)機(jī)制,適合證書認(rèn)證場(chǎng)景
缺點(diǎn):加密效率低,通常用于加密對(duì)稱密鑰
// RSA 工具類(生成公鑰私鑰對(duì))
public class RSAUtils {
private static final int KEY_SIZE = 1024;
private static final String ALGORITHM = "RSA";
public static Map<String, String> generateKeyPair() throws Exception {
KeyPairGenerator generator = KeyPairGenerator.getInstance(ALGORITHM);
generator.initialize(KEY_SIZE);
KeyPair pair = generator.generateKeyPair();
return Map.of(
"publicKey", Base64.getEncoder().encodeToString(pair.getPublic().getEncoded()),
"privateKey", Base64.getEncoder().encodeToString(pair.getPrivate().getEncoded())
);
}
}
三、實(shí)戰(zhàn)方案一:基于 AOP 的透明加解密
1. 核心原理
通過(guò)自定義注解標(biāo)記需要加解密的接口,利用 Spring AOP 在方法調(diào)用前后自動(dòng)處理加解密邏輯,實(shí)現(xiàn)業(yè)務(wù)代碼零侵入。
2. 實(shí)現(xiàn)步驟
(1)定義加解密注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Encrypt {
// 排除字段(如時(shí)間戳等無(wú)需加密字段)
String[] excludeFields() default {};
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Decrypt {
// 解密失敗是否拋出異常
boolean throwOnFailure() default true;
}
(2)編寫 AOP 切面
@Aspect
@Component
public class DataEncryptAspect {
@Around("@annotation(Encrypt)")
public Object encryptAround(ProceedingJoinPoint joinPoint) throws Throwable {
// 執(zhí)行原始方法
Object result = joinPoint.proceed();
// 對(duì)響應(yīng)結(jié)果進(jìn)行AES加密
return AESUtils.encrypt(JSON.toJSONString(result));
}
@Around("@annotation(Decrypt)")
public Object decryptAround(ProceedingJoinPoint joinPoint) throws Throwable {
// 獲取請(qǐng)求參數(shù)(假設(shè)參數(shù)為JSON字符串)
Object[] args = joinPoint.getArgs();
String encryptedData = (String) args[0];
// 解密請(qǐng)求參數(shù)
String decryptedData = AESUtils.decrypt(encryptedData);
// 替換原始參數(shù)為解密后的數(shù)據(jù)
args[0] = decryptedData;
return joinPoint.proceed(args);
}
}
(3)控制器使用示例
@RestController
@RequestMapping("/api")
public class UserController {
@PostMapping("/register")
@Decrypt
public UserRegisterResponse register(@RequestBody String encryptedData) {
// 處理解密后的明文數(shù)據(jù)
UserRegisterRequest request = JSON.parseObject(encryptedData, UserRegisterRequest.class);
// 業(yè)務(wù)邏輯...
return new UserRegisterResponse("注冊(cè)成功", request.getUserId());
}
@GetMapping("/profile")
@Encrypt
public UserProfile getProfile(@RequestParam String userId) {
// 業(yè)務(wù)邏輯獲取用戶信息
return new UserProfile("張三", "138****1234");
}
}
3. 方案優(yōu)勢(shì)
- 低侵入性:僅需在接口方法添加注解
- 靈活配置:可自定義排除字段和異常處理策略
- 適用場(chǎng)景:適合對(duì)單個(gè)接口細(xì)粒度控制的場(chǎng)景
四、實(shí)戰(zhàn)方案二:全局過(guò)濾器實(shí)現(xiàn)請(qǐng)求響應(yīng)加解密
1. 核心原理
通過(guò)實(shí)現(xiàn) Filter 或 HandlerInterceptor,在請(qǐng)求進(jìn)入控制器前解密參數(shù),響應(yīng)離開前加密結(jié)果,實(shí)現(xiàn)全局統(tǒng)一加解密。
2. 實(shí)現(xiàn)步驟
(1)自定義加解密過(guò)濾器
@Component
public class DataEncryptFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 處理請(qǐng)求解密(假設(shè)請(qǐng)求體為加密的JSON)
HttpServletRequest httpRequest = (HttpServletRequest) request;
String encryptedBody = IOUtils.toString(httpRequest.getInputStream(), StandardCharsets.UTF_8);
String decryptedBody = AESUtils.decrypt(encryptedBody);
// 包裝請(qǐng)求體為可重復(fù)讀取的流
HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper(httpRequest, decryptedBody);
// 處理響應(yīng)加密
final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
HttpServletResponseWrapper responseWrapper = new HttpServletResponseWrapper((HttpServletResponse) response, buffer);
chain.doFilter(requestWrapper, responseWrapper);
// 對(duì)響應(yīng)結(jié)果加密并寫出
String encryptedResult = AESUtils.encrypt(buffer.toString());
response.getWriter().write(encryptedResult);
}
}
// 請(qǐng)求包裝類(重寫getInputStream)
class HttpServletRequestWrapper extends HttpServletRequestWrapper {
private final String body;
public HttpServletRequestWrapper(HttpServletRequest request, String body) {
super(request);
this.body = body;
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bis = new ByteArrayInputStream(body.getBytes());
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bis.read();
}
// 省略其他抽象方法實(shí)現(xiàn)
};
}
}
(2)配置過(guò)濾器生效
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<DataEncryptFilter> encryptFilterRegistration() {
FilterRegistrationBean<DataEncryptFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new DataEncryptFilter());
registration.addUrlPatterns("/api/v1/**"); // 配置需要加解密的接口路徑
registration.setOrder(Ordered.HIGHEST_PRECEDENCE); // 保證過(guò)濾器優(yōu)先執(zhí)行
return registration;
}
}
3. 方案優(yōu)勢(shì)
- 全局統(tǒng)一:一次配置,所有接口自動(dòng)加解密
- 高性能:基于流處理,避免反射帶來(lái)的性能損耗
- 適用場(chǎng)景:適合前后端分離項(xiàng)目的全局?jǐn)?shù)據(jù)加密
五、實(shí)戰(zhàn)方案三:自定義 MessageConverter 實(shí)現(xiàn)透明加解密
1. 核心原理
重寫 Spring MVC 的 HttpMessageConverter,在請(qǐng)求參數(shù)解析和響應(yīng)數(shù)據(jù)序列化階段自動(dòng)完成加解密,與框架深度整合。
2. 實(shí)現(xiàn)步驟
(1)自定義加解密轉(zhuǎn)換器
public class EncryptingHttpMessageConverter extends AbstractHttpMessageConverter<Object> {
@Override
protected boolean supports(Class<?> clazz) {
return true; // 支持所有類型
}
@Override
protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
// 讀取加密的請(qǐng)求體并解密
String encrypted = IOUtils.toString(inputMessage.getBody(), StandardCharsets.UTF_8);
String decrypted = AESUtils.decrypt(encrypted);
return JSON.parseObject(decrypted, clazz);
}
@Override
protected void writeInternal(Object object, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
// 將響應(yīng)對(duì)象加密后寫出
String plain = JSON.toJSONString(object);
String encrypted = AESUtils.encrypt(plain);
outputMessage.getBody().write(encrypted.getBytes(StandardCharsets.UTF_8));
}
}
(2)注冊(cè)自定義轉(zhuǎn)換器
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new EncryptingHttpMessageConverter());
// 保留默認(rèn)轉(zhuǎn)換器(可選)
// converters.addAll(Collections.singletonList(new MappingJackson2HttpMessageConverter()));
}
}
3. 方案優(yōu)勢(shì)
- 框架級(jí)整合:與 Spring MVC 數(shù)據(jù)綁定機(jī)制深度融合
- 類型安全:自動(dòng)處理對(duì)象與加密字符串的轉(zhuǎn)換
- 適用場(chǎng)景:適合對(duì)請(qǐng)求 / 響應(yīng)格式有嚴(yán)格控制的場(chǎng)景
六、三種方案對(duì)比與選型建議
方案一:AOP 注解
- 侵入性:低
- 性能:中
- 靈活性:接口級(jí)控制
- 適用場(chǎng)景:部分接口需要加解密
- 方案二:全局過(guò)濾器
- 侵入性:中
- 性能:高
- 靈活性:路徑級(jí)控制
- 適用場(chǎng)景:前后端分離項(xiàng)目全局加密
方案三:MessageConverter
- 侵入性:高
- 性能:最高
- 靈活性:框架級(jí)控制
- 適用場(chǎng)景:統(tǒng)一請(qǐng)求響應(yīng)格式場(chǎng)景
七、生產(chǎn)環(huán)境最佳實(shí)踐
1. 密鑰管理方案
- 禁止硬編碼:通過(guò)
Spring Config或配置中心(如 Nacos)管理密鑰 - 密鑰輪換:定期生成新密鑰,舊密鑰逐步淘汰
- 硬件安全:敏感系統(tǒng)使用 HSM(硬件安全模塊)存儲(chǔ)密鑰
2. 異常處理機(jī)制
@RestControllerAdvice
public class EncryptExceptionHandler {
@ExceptionHandler(DecryptionException.class)
public ResponseEntity<String> handleDecryptionError(DecryptionException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body("數(shù)據(jù)解密失?。? + e.getMessage());
}
}
3. 性能優(yōu)化技巧
- 壓縮后加密:對(duì)大體積數(shù)據(jù)先壓縮再加密(Gzip 壓縮可減少 50% 數(shù)據(jù)量)
- 異步加解密:使用 CompletableFuture 實(shí)現(xiàn)加解密與業(yè)務(wù)邏輯并行處理
- 緩存加密結(jié)果:對(duì)高頻訪問(wèn)接口的加密結(jié)果進(jìn)行緩存
八、總結(jié)
Spring Boot 提供了從接口級(jí)到框架級(jí)的完整加解密解決方案,核心是根據(jù)業(yè)務(wù)場(chǎng)景選擇合適的實(shí)現(xiàn)方式:
- 追求靈活性選 AOP 注解
- 追求統(tǒng)一性選 全局過(guò)濾器
- 追求框架整合選 MessageConverter
無(wú)論哪種方案,都需注意密鑰安全和異常處理。通過(guò)本文的源碼示例,開發(fā)者可快速在項(xiàng)目中落地接口數(shù)據(jù)加解密功能,在保障數(shù)據(jù)安全的同時(shí),最小化對(duì)現(xiàn)有業(yè)務(wù)的影響。
在數(shù)據(jù)安全日益重要的今天,掌握接口加解密技術(shù),不僅是程序員的核心競(jìng)爭(zhēng)力,更是保障系統(tǒng)安全的必備技能。選擇合適的方案,讓數(shù)據(jù)在網(wǎng)絡(luò)傳輸中穿上 “防彈衣”,這才是現(xiàn)代后端開發(fā)的正確姿勢(shì)。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring?AI?+?ollama?本地搭建聊天?AI?功能
這篇文章主要介紹了Spring?AI?+?ollama?本地搭建聊天?AI?,本文通過(guò)實(shí)例圖文相結(jié)合給大家講解的非常詳細(xì),需要的朋友可以參考下2024-11-11
Java 中的進(jìn)制轉(zhuǎn)換與編碼機(jī)制詳解
在 Java 編程領(lǐng)域,進(jìn)制轉(zhuǎn)換是一項(xiàng)極為基礎(chǔ)且重要的技能,下面給大家介紹Java 中的進(jìn)制轉(zhuǎn)換與編碼機(jī)制,感興趣的朋友一起看看吧2025-04-04
Java如何按16進(jìn)制發(fā)送和接收TCP指令
這篇文章主要介紹了Java如何按16進(jìn)制發(fā)送和接收TCP指令問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09
Spring Boot結(jié)成MyBatis-Plus最全配置指南
本文主要介紹了Spring Boot結(jié)成MyBatis-Plus最全配置指南,包括依賴引入、配置數(shù)據(jù)源、Mapper 掃描、基本CRUD操作等,具有一定的參考價(jià)值,感興趣的可以了解一下2025-03-03
Java編程實(shí)現(xiàn)統(tǒng)計(jì)一個(gè)字符串中各個(gè)字符出現(xiàn)次數(shù)的方法
這篇文章主要介紹了Java編程實(shí)現(xiàn)統(tǒng)計(jì)一個(gè)字符串中各個(gè)字符出現(xiàn)次數(shù)的方法,涉及java針對(duì)字符串的遍歷、判斷、運(yùn)算等相關(guān)操作技巧,需要的朋友可以參考下2017-12-12
Mybatis useGeneratedKeys參數(shù)用法及問(wèn)題小結(jié)
這篇文章主要介紹了Mybatis useGeneratedKeys參數(shù)用法及遇到的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05
頁(yè)面的緩存與不緩存設(shè)置及html頁(yè)面中meta的作用
這篇文章主要介紹了頁(yè)面的緩存與不緩存設(shè)置及html頁(yè)面中meta的作用的相關(guān)資料,需要的朋友可以參考下2016-05-05
詳解全局事務(wù)注解@GlobalTransactional的識(shí)別
這篇文章主要為大家介紹了詳解全局事務(wù)注解@GlobalTransactional的識(shí)別源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12

