You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot+Angular请求加密响应解密低侵入实现方案咨询

网络层请求响应非明文传输的低代码实现方案(Spring Boot + Angular)

后端(Spring Boot):全局请求解密/响应加密

利用Spring MVC的RequestBodyAdvice和ResponseBodyAdvice实现全局拦截,无需修改单个控制器方法。

1. 实现请求解密处理器

通过RequestBodyAdvice在请求体被解析前完成解密:

@ControllerAdvice
public class EncryptedRequestBodyAdvice implements RequestBodyAdvice {

    @Value("${encryption.aes.key}")
    private String aesSecretKey; // 从配置文件读取密钥,需符合AES长度要求(16/24/32字节)

    @Override
    public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        // 可通过methodParameter过滤不需要加密的接口,比如健康检查
        return !methodParameter.getMethod().getName().contains("health");
    }

    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
        // 读取加密请求体并解密
        byte[] encryptedBytes = StreamUtils.copyToByteArray(inputMessage.getBody());
        byte[] decryptedBytes = AESEncryptor.decrypt(encryptedBytes, aesSecretKey);
        
        return new HttpInputMessage() {
            @Override
            public InputStream getBody() throws IOException {
                return new ByteArrayInputStream(decryptedBytes);
            }

            @Override
            public HttpHeaders getHeaders() {
                return inputMessage.getHeaders();
            }
        };
    }

    // 其余默认方法直接返回父类实现即可
}

2. 实现响应加密处理器

通过ResponseBodyAdvice在响应体返回前完成加密:

@ControllerAdvice
public class EncryptedResponseBodyAdvice implements ResponseBodyAdvice<Object> {

    @Value("${encryption.aes.key}")
    private String aesSecretKey;

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return !returnType.getMethod().getName().contains("health");
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (body == null) return null;

        try {
            // 将响应对象序列化为JSON字符串后加密
            String jsonBody = new ObjectMapper().writeValueAsString(body);
            byte[] encryptedBytes = AESEncryptor.encrypt(jsonBody.getBytes(StandardCharsets.UTF_8), aesSecretKey);
            
            // 设置响应头,告知前端数据类型
            response.getHeaders().setContentType(MediaType.APPLICATION_OCTET_STREAM);
            return encryptedBytes;
            // 若采用Base64传输,可替换为:return Base64.getEncoder().encodeToString(encryptedBytes),并修改Content-Type为application/json
        } catch (Exception e) {
            throw new RuntimeException("响应加密失败", e);
        }
    }
}

3. AES加密工具类

public class AESEncryptor {
    private static final String ALGORITHM = "AES";
    private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding";

    public static byte[] encrypt(byte[] data, String secretKey) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), ALGORITHM);
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(Cipher.ENCRYPT_MODE, keySpec);
        return cipher.doFinal(data);
    }

    public static byte[] decrypt(byte[] encryptedData, String secretKey) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), ALGORITHM);
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(Cipher.DECRYPT_MODE, keySpec);
        return cipher.doFinal(encryptedData);
    }
}

后端注意事项

  • 密钥需妥善存储,生产环境建议使用Spring Cloud Config加密配置或密钥管理服务
  • 通过supports方法精准控制需要加密的接口范围
  • 处理解密失败的异常,返回友好的错误响应

前端(Angular):全局请求加密/响应解密

利用Angular的HttpInterceptor实现全局HTTP拦截,无需修改单个请求代码。

1. 安装依赖(可选)

若使用第三方加密库,可安装crypto-js:

npm install crypto-js

2. 实现请求加密拦截器

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';
import { environment } from '../environments/environment';
import * as CryptoJS from 'crypto-js';

@Injectable()
export class EncryptInterceptor implements HttpInterceptor {
  private readonly aesKey = environment.aesSecretKey;

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    // 跳过不需要加密的请求
    if (req.url.includes('/health') || req.responseType === 'blob') {
      return next.handle(req);
    }

    let encryptedBody: string;
    if (req.body) {
      const jsonStr = JSON.stringify(req.body);
      encryptedBody = CryptoJS.AES.encrypt(jsonStr, this.aesKey).toString();
    }

    // 克隆请求并替换加密后的请求体
    const modifiedReq = req.clone({
      body: encryptedBody,
      headers: req.headers.set('Content-Type', 'application/json')
    });

    return next.handle(modifiedReq);
  }
}

3. 实现响应解密拦截器

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { environment } from '../environments/environment';
import * as CryptoJS from 'crypto-js';

@Injectable()
export class DecryptInterceptor implements HttpInterceptor {
  private readonly aesKey = environment.aesSecretKey;

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (req.url.includes('/health') || req.responseType === 'blob') {
      return next.handle(req);
    }

    return next.handle(req).pipe(
      map(event => {
        if (event instanceof HttpResponse && event.body) {
          // 解密响应体并解析为JSON
          const decryptedStr = CryptoJS.AES.decrypt(event.body, this.aesKey).toString(CryptoJS.enc.Utf8);
          return event.clone({ body: JSON.parse(decryptedStr) });
        }
        return event;
      })
    );
  }
}

4. 注册拦截器

在AppModule中注册拦截器:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { EncryptInterceptor } from './encrypt.interceptor';
import { DecryptInterceptor } from './decrypt.interceptor';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, HttpClientModule],
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: EncryptInterceptor, multi: true },
    { provide: HTTP_INTERCEPTORS, useClass: DecryptInterceptor, multi: true }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

前端注意事项

  • 密钥从环境变量读取,避免硬编码
  • 拦截器可通过URL、响应类型过滤不需要加密的请求
  • 处理解密失败的异常,给出用户提示

工具包推荐

  • 后端:Java原生javax.crypto包(无需额外依赖)、Apache Commons Codec(简化Base64处理)
  • 前端:crypto-js(API简洁,易上手)、Web Crypto API(原生支持,无需依赖)

内容的提问来源于stack exchange,提问作者Rikky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 11:03:13