wechatpay-apiv3 / wechatpay-apache-httpclient

微信支付 APIv3 Apache HttpClient装饰器(decorator)
https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pages/index.shtml
Apache License 2.0
674 stars 251 forks source link

请问如何构造测试回调数据? #172

Closed Alickx closed 1 year ago

Alickx commented 1 year ago

我按照微信官方回调回来的请求数据构造,可是显示验签失败,微信官方的请求是可以正常验签的。 我该如何构造本地环境下的回调数据?

xy-peng commented 1 year ago

贴一下你请求数据构造的代码?以及验签失败时的错误信息/日志?

Alickx commented 1 year ago

贴一下你请求数据构造的代码?以及验签失败时的错误信息/日志?

我是直接拿Apifox构造请求的,header和body都是一模一样。

xy-peng commented 1 year ago

我是直接拿Apifox构造请求的,header和body都是一模一样。

你的意思是,你使用发包工具构造了一个跟回调一模一样的 HTTP 请求,发往你的服务器,但是验签失败?

你看看是不是时间戳过期了,超过5分钟的请求会验证失败的。

Alickx commented 1 year ago

这个时间戳是指请求头里面的wechatpay-timestamp吗,我尝试取现在时间的时间戳也还是验签失败。我需要发body内容上来给你看一下吗?

xy-peng commented 1 year ago

这个时间戳是指请求头里面的wechatpay-timestamp吗,我尝试取现在时间的时间戳也还是验签失败。我需要发body内容上来给你看一下吗?

提供一组你用来测试的完整数据吧,包括商户号,但记得隐去私钥信息。也附上贴下你的实验代码。

Alickx commented 1 year ago
package com.gaojing.voicelive.commons.starter.wechat.client;

import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager;
import com.wechat.pay.contrib.apache.httpclient.notification.Notification;
import com.wechat.pay.contrib.apache.httpclient.notification.NotificationHandler;
import com.wechat.pay.contrib.apache.httpclient.notification.NotificationRequest;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;

public class NotificationHandlerTest {

    private static final String privateKey = "";
    private static final String merchantId = "1615006484"; // 商户号
    private static final String merchantSerialNumber = "1A34592846AB596ABAA8C1B7AF64EA1C76F4AE46"; // 商户证书序列号
    private static final String apiV3Key = ""; // apiV3密钥
    private static final String wechatPaySerial = "7A0846250EBE9CD870FB5F4CE1C7646021642D87"; // 平台证书序列号
    private static final String nonce = "TGe6jKXcdtrX4ztC8wwuIF49rldB4Twl"; // 请求头Wechatpay-Nonce
//    private static final String timestamp = "1666683836";// 请求头Wechatpay-Timestamp

    private static final String timestamp = "1667286749";// 请求头Wechatpay-Timestamp
    private static final String signature = "dVOJj/oFQyYTGbUJ5wOLzNda4bTsmJA0nVF4NEkgP+q27yyW12Kq8Y6+lHYYqifRL+0rdNLNjQQfkwmZwpThKg/L0mocw7OADkZZh7y8y4jJ9MNETEmSWybt6GlkzkcpjyE1jjnDw0VUObz+Oiano7kXaap+BpOJDxQTlgqwv80hs1/lBymNLVCuP9kSiKRxPkHj31fOY9sH6+7ObU3DuyQFz25svucm5pjZu4gASfhqlfZxuu4Gxfp3vy/EfhsYufRNFo2DKZ0+nI2H7z2M6mMqvEQ29aUPHMsyu7MgnYAsSHQpM5ZK9ZRK80+/TM1xaD6iLvlI+Y/zPgNKs9CTQg==";// 请求头Wechatpay-Signature
    private static final String body = "{  \"id\": \"12d3a6b2-a5d4-5200-8ffa-57ece90c04cd\",  \"create_time\": \"2022-10-25T15:43:44+08:00\",  \"resource_type\": \"encrypt-resource\",  \"event_type\": \"COMPLAINT.CREATE\",  \"summary\": \"新投诉生成\",  \"resource\": {    \"original_type\": \"complaint\",    \"algorithm\": \"AEAD_AES_256_GCM\",    \"ciphertext\": \"tXTXyaJkHKepi/Oivl4A0M5s7RDkGySa7JhNaRIukS/grMZteJsnpq0t/5Gzq5aLQcv7N0KRYpaTPWESsFkEaRpnjRdhsJB32quCXtaOjtASqdyBSYIHxXD+SRJcOLcWB9/lzTQUxeYMU/BBOL96nuQkEqOVz5X1fPQ/8OfyctDUhR16PhhYjjct1qQHVNiT+SrF+3lR7R29eJPtml2BCV5eZxu/Tb8zE4n47m4z+YMKmYreWbkZjbj1OtK/fxGIJX9KjE881czdXTd2pYJIsDuFn8+eaSRVmCTOsJ7B0WiGuwmMkKOvf34R2yOX5ZzFyYH0NBwBGMw/O1AOpjHcf4B4/DhkUCqaA9KySonbvsCB/5hfdn/L/Nx+Dbmt9FlT9eXy7SWdVT5b0eeJkAHuLWmt7sxBkw350zsQ8/X1YY7RptNaDVao6vadoIftcG1vRxZumSH4DMJtYBd6mq0P3APXDqjdLfXbsN671Dm8rMdJ322dXq13L9WTBrPuoyBIM47Fq2e87+/pecqP7bwBb2drngAVzxrQXXQGm9kWCLOXILqycS0Dul+PQSwsiAIW\",    \"associated_data\": \"complaint\",    \"nonce\": \"TGNWe8KWMiR2\"  }}";
    private Verifier verifier; // 验签器
    private static CertificatesManager certificatesManager; // 平台证书管理器

    @Before
    public void setup() throws Exception {
        PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(privateKey);
        // 获取证书管理器实例
        certificatesManager = CertificatesManager.getInstance();
        // 向证书管理器增加需要自动更新平台证书的商户信息
        certificatesManager.putMerchant(merchantId, new WechatPay2Credentials(merchantId,
                        new PrivateKeySigner(merchantSerialNumber, merchantPrivateKey)),
                apiV3Key.getBytes(StandardCharsets.UTF_8));
        // 从证书管理器中获取verifier
        verifier = certificatesManager.getVerifier(merchantId);
    }

    @Test
    public void notificationHandlerTest() throws Exception {
        // 构建request,传入必要参数
        NotificationRequest request = new NotificationRequest.Builder().withSerialNumber(wechatPaySerial)
                .withNonce(nonce)
                .withTimestamp(timestamp)
                .withSignature(signature)
                .withBody(body)
                .build();
        NotificationHandler handler = new NotificationHandler(verifier, apiV3Key.getBytes(StandardCharsets.UTF_8));
        // 验签和解析请求体
        Notification notification = handler.parse(request);
        Assert.assertNotNull(notification);
        System.out.println(notification);
    }

}
xy-peng commented 1 year ago

timestamp = "1667286749" \"create_time\": \"2022-10-25T15:43:44+08:00\"

时间戳是参与签名的,你只改时间戳是不行的。看这两个时间差得有点大,是不是你手工调整过参数?真实的数据,而且要在5分钟之内,才能验签成功。

Alickx commented 1 year ago

我将两者都修改成现在的时间还是验签失败。真实数据可以验签成功,可是自己构造回调请求无法验签成功。 timestamp = "1667294373" create_time = "2022-11-01T17:19:33+08:00"

xy-peng commented 1 year ago

真实请求改了就会验签不通过。如果你能改,岂不是很容易被坏人利用?

如果你希望自测,按规则构造签名串,用私钥(建议随机生成,不要用商户API私钥)计算签名,再使用对应公钥/证书验签。

Alickx commented 1 year ago

真实请求改了就会验签不通过。如果你能改,岂不是很容易被坏人利用?

如果你希望自测,按规则构造签名串,用私钥(建议随机生成,不要用商户API私钥)计算签名,再使用对应公钥/证书验签。

好的吧,谢谢你的解答