wechatpay-apiv3 / wechatpay-java

微信支付 APIv3 的官方 Java Library
Apache License 2.0
961 stars 209 forks source link

微信支付成功后,异步通知 NotificationParser.parse 解密数据异常 #112

Closed pyrange closed 1 year ago

pyrange commented 1 year ago

错误描述

微信支付成功,异步通知解密数据异常

运行环境

java:JDK17 依赖微信sdk:wechatpay-java;0.2.4版本

示例代码

image


    // 使用自动更新平台证书的RSA配置
    // 一个商户号只能初始化一个配置,否则会因为重复的下载任务报错
    RSAAutoCertificateConfig config = new RSAAutoCertificateConfig.Builder()
            .merchantId(WeiXinPayConstant.MCH_ID)
            .privateKey(WeiXinPayConstant.MCH_PRIVATE_KEY)
            .merchantSerialNumber(WeiXinPayConstant.MCH_SERIAL_NO)
            .apiV3Key(WeiXinPayConstant.API_V3_KEY)
            .build();

异常信息:

com.wechat.pay.java.core.exception.ValidationException: Processing WechatPay notification,signature verification failed,signType[WECHATPAY2-SHA256-RSA2048] serial[72A58B94F5350B13A124585D15BF88C1E55AB350]    message[1672906824
WYDi5b6dyyi36Cry6Vd95cYW5EOrwwNo
{"summary":"支付成功","event_type":"TRANSACTION.SUCCESS","create_time":"2023-01-05T16:16:20+08:00","resource":{"original_type":"transaction","algorithm":"AEAD_AES_256_GCM","ciphertext":"dFZoL6Qa18H3/R0fpBvviskQ1xVaXQDkRSJETChAtBcYfmNvBOqmipI8u1yTTl5ddgjarOdAuK5npSjMjfc1/OEPaNx91R2kG82e3NFaXP3csvtSLCNRN6h1MFBlMPqHVGk8SoOKqgGQAxAmzeLUzUlRI9gQm8GDRvJYzsIkTdWs//2yZZAdEOLXe29Uu+Zj41Te+/iHR0JkmHup9XXMSOZ+cjwmoTlycYd9b0u7j1O4f54fG78jsP76jt6YhniJPhi1nN9Mb2v4wYzH6LHA3wWN4oPLQmXMORL8F+gqm88yyrf79XlcZgovTXM1cUIklDb0pGyennQXSfrzz7Z8dxPmmiLo8zp8XHMUtsb81W8lV6oC4c/nykd7j6NPoI8F6VUYDptCH6aZu/nvsMyCRRvalSFHvLYwIIRtNc1/VB49KKF1H4EncY/lx3gOdI4FSrt8Q/wYt+QPqZ/1QEs0QlFYW98TlXPtCC9pgveR4gZRUHdrvYwxwJT2Gn5rQn18vhZDfxrFaBZLxLYruNyyGRXkBMPqsa9i0Exu6e/gcEcvylo9yQUoJ1GDliOIBJ8eF9rELEos","associated_data":"transaction","nonce":"Zs7DNh4Njdvf"},"resource_type":"encrypt-resource","id":"a179bbb2-257f-5c07-826a-287d39b995f6"}
]   sign[hpq6R1V4LO25TYN97VnhkPrRheXyn7WrtmYDLkeI4eF7O248YXYJC6TLCp/T57lNZBAyPtHz+4K0Rm7SqXAQzmGh/OvlAi3FTvXk/Wm8FOp59VqOerxw7HYD3UFItAS0rpozoIC5ha5b2FHqmGCp5l7OGIXLf9PnGW2s551im2BkBLb+1WW2f6udJywoGL/YGVZ4Jl7bwMFYf64GZAc0AIGQqRWBrL7zIiL8Nw4ajBZTiwDOlZiSJg9vzVaHJyj4nSKe8wPy5ZcPq2Hd4JZ0VUvakhiqyxjsz4KJE8nB8HQicMgBSZpuJPRPzxaWd/DB9x73XmCY2A26DRFfs0mZNA==]
    at com.wechat.pay.java.core.notification.NotificationParser.validateRequest(NotificationParser.java:93)
    at com.wechat.pay.java.core.notification.NotificationParser.parse(NotificationParser.java:49)
    at com.pyrange.app.main.web.service.payment.weixin.WeixinPaymentServiceImpl.paymentSuccessNotify(WeixinPaymentServiceImpl.java:367)
    at com.pyrange.app.main.web.controller.WeixinPaymentController.paymentSuccessNotify(WeixinPaymentController.java:37)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752)
    at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:57)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752)
    at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:58)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703)
    at com.pyrange.app.main.web.controller.WeixinPaymentController$$SpringCGLIB$$0.paymentSuccessNotify(<generated>)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1080)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:973)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1003)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:906)
    at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:731)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:880)
    at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1739)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.base/java.lang.Thread.run(Thread.java:833)

重现bug的步骤

  1. 微信小程序支付
  2. 收到微信通知

预期行为

正常解析密文

导致错误的代码片段

Transaction parse = parser.parse(requestParam, Transaction.class);

操作系统

win10

Java 版本

java 17

wechatpay-java 版本

0.2.4

其他信息

xy-peng commented 1 year ago

body要使用原始的报文,而不是 toJSONString() 的字符串。经过序列化和反序列化之后,跟原文不一致。

402626224 commented 1 year ago
public ResponseEntity<WxResultInfoVo> wxNotify(
        @RequestHeader("wechatpay-serial") String serialNumber,
        @RequestHeader("wechatpay-nonce") String nonce,
        @RequestHeader("wechatpay-signature") String signature,
        @RequestHeader("wechatpay-timestamp") String timestamp,
        @RequestHeader("wechatpay-signature-type") String signType,
        HttpServletRequest request
) {
        String body = IOUtils.toString(request.getInputStream());
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(serialNumber.trim())
                .nonce(nonce.trim())
                .signature(signature.trim())
                .timestamp(timestamp.trim())
                // 若未设置signType,默认值为 WECHATPAY2-SHA256-RSA2048
                .signType(signType.trim())
                .body(body)
                .build();
            NotificationParser parser = new NotificationParser(config);
            Map map = parser.parse(requestParam, Map.class);

这样子也是验签不通过

Roc1991x commented 11 months ago

能给一个获取原始body的例子么?

liguangling-lgl commented 8 months ago
private String getRequestBody(HttpServletRequest request) {
    ByteArrayOutputStream body = new ByteArrayOutputStream();
    try {
        ServletInputStream inputStream = request.getInputStream();
        byte[] buffer = new byte[1024];
        for (int length; (length = inputStream.read(buffer)) != -1; ) {
            body.write(buffer, 0, length);
        }
    } catch (IOException ex) {
        log.error("支付回调,读取数据流异常", ex);
    }
    log.info("支付回调,通知消息体:{}", body);
    return body.toString();
}

有的极少订单回调会报这个解签错误,大部分订单可以成功,这个是body读取的代码示例,不清楚为什么会这样,微信sdk版本是0.2.7

AndromedaX7 commented 4 months ago

感谢大佬们先踩坑了,让咱吃了现成的了

helloWorld233333333 commented 3 months ago
private String getRequestBody(HttpServletRequest request) {
    ByteArrayOutputStream body = new ByteArrayOutputStream();
    try {
        ServletInputStream inputStream = request.getInputStream();
        byte[] buffer = new byte[1024];
        for (int length; (length = inputStream.read(buffer)) != -1; ) {
            body.write(buffer, 0, length);
        }
    } catch (IOException ex) {
        log.error("支付回调,读取数据流异常", ex);
    }
    log.info("支付回调,通知消息体:{}", body);
    return body.toString();
}

有的极少订单回调会报这个解签错误,大部分订单可以成功,这个是body读取的代码示例,不清楚为什么会这样,微信sdk版本是0.2.7

我猜你要找的是‘签名探测流量’,https://pay.weixin.qq.com/docs/merchant/development/interface-rules/signature-verification.html