Spring Boot中Stripe Webhook签名验证失败问题求助
Stripe Webhook签名验证失败:"Signature not found" 问题排查与解决
核心原因:请求体被修改或读取方式不正确
Stripe的Webhook签名是基于原始请求体的字节流计算的,如果Spring Boot在读取请求体时对内容做了修改(比如编码转换、自动去除空白符、格式化JSON等),就会导致计算出的签名和Stripe发送的签名不一致,触发"Signature not found"或签名不匹配错误。
解决步骤
1. 避免使用@RequestBody直接读取请求体
@RequestBody会自动解析请求体并转换成字符串,这个过程中可能会改变原始字节的编码或格式。正确的做法是读取原始字节流,并且保证请求体只被读取一次(ServletInputStream只能读取一次,所以需要缓存)。
2. 使用ContentCachingRequestWrapper缓存请求体
通过Spring提供的ContentCachingRequestWrapper包装请求,缓存原始字节流,方便后续读取:
- 先注册一个过滤器:
public class RequestBodyCachingFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request); filterChain.doFilter(wrappedRequest, response); } }
- 在控制器中读取缓存的原始字节:
@PostMapping("/event") public ResponseEntity<String> processStripeEvents(HttpServletRequest request) { String sigHeader = request.getHeader("Stripe-Signature"); // 从缓存中获取原始请求体字节 byte[] rawRequestBody = ((ContentCachingRequestWrapper) request).getContentAsByteArray(); try { Event event = Webhook.constructEvent(rawRequestBody, sigHeader, "whsec_your_signing_secret"); // 处理事件逻辑 return ResponseEntity.ok("Event processed successfully"); } catch (SignatureVerificationException e) { return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Invalid signature: " + e.getMessage()); } catch (JsonProcessingException e) { return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Invalid event payload"); } }
3. 排查Webhook.site的影响
Webhook.site本身不会修改请求体,但要确认:
- 测试时Stripe控制台的Webhook URL是否指向你的Spring Boot服务,而非Webhook.site。如果之前用Webhook.site测试后没改回自己的服务地址,你的接口根本收不到Stripe的事件,自然会验证失败。
- 可以用Webhook.site对比Stripe发送的原始请求体和你的服务接收的请求体,看两者是否完全一致(包括换行符、空格、编码等)。
4. 其他关键检查点
- 确认签名密钥是Stripe控制台中对应Webhook端点的签名密钥(不是API密钥),每个Webhook端点有独立的签名密钥,不要混用。
- 检查网关/代理(如Nginx)是否修改了请求体或请求头,比如自动压缩、修改Content-Type等,这些都会破坏签名验证。
- 保证读取请求体时使用UTF-8编码,Stripe发送的请求体默认是UTF-8编码,不要擅自更改编码格式。
内容的提问来源于stack exchange,提问作者suraj bahl
相关产品推荐
相关产品推荐

