在 Spring Boot 中,HttpServletRequest 的 InputStream 默认只能读取一次。原因是底层的流在读取后,内容不会被缓存,导致流在后续处理时无法再次读取。
要解决该问题,同时满足 RSA 解密参数、验证签名,并重新构造请求 的需求,可以按照以下步骤实现:
实现方案
1. 核心逻辑步骤
拦截请求:
使用 Filter 或 HandlerInterceptor 捕获请求。
读取请求内容并缓存:
将 HttpServletRequest 包装为可重复读取的请求(例如,ContentCachingRequestWrapper 或自定义包装类)。
处理解密和签名验证:
使用 RSA 私钥解密参数。
验签逻辑验证请求数据的完整性。
重构请求并传递:
创建一个新的 HttpServletRequestWrapper,将解密后的参数重新注入。
将新构造的请求传递给后续的处理逻辑。
2. 代码实现
自定义过滤器
import org.springframework.stereotype.Component;
import javax.crypto.Cipher;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.Signature;
import java.util.stream.Collectors;
@Component
public class DecryptFilter implements Filter {
// 配置 RSA 私钥
private final PrivateKey privateKey = YourPrivateKeyProvider.getPrivateKey();
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (request instanceof HttpServletRequest) {
CachedBodyHttpServletRequest wrappedRequest = new CachedBodyHttpServletRequest((HttpServletRequest) request);
// 读取请求体
String body = wrappedRequest.getCachedBody();
System.out.println("Original Request Body: " + body);
// 解密请求参数
String decryptedBody = decryptRSA(body)<