fudiwei / DotNetCore.SKIT.FlurlHttpClient.Wechat

可能是全网最完整的 C# 版微信 SDK,封装全部已知的微信 OpenAPI,包含微信公众平台(订阅号+服务号+小程序+小游戏+小商店+视频号)、微信开放平台、微信商户平台(微信支付+微企付)、企业微信、微信广告平台、微信智能对话开放平台等模块,可跨平台。持续随官方更新,欢迎 Star/Fork/PR。QQ 交流群 875580418【满】、930461548【满】、611974621。
https://github.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient
MIT License
1.47k stars 285 forks source link

DotNet 回调验签报错 #146

Closed Vin-Cente closed 1 month ago

Vin-Cente commented 1 month ago

看了好几天的文档和Issue已发现的问题,我感觉自己还是解决不了。 故申请Issue联系开发大大 现在我知道验签之前要将平台证书放到那个管理器中 现在添加平台证书的时候报错,所以验签的代码也没有执行到 还有就是两个证书我可能搞混了,我想知道怎么区分商户证书和平台证书 我的DotNet 6 项目,在Program中配置了服务,代码如下:

//配置微信支付服务
var manager = new InMemoryCertificateManager();
var options = new WechatTenpayClientOptions()
{
    MerchantId = "",
    MerchantV3Secret = "",
    MerchantCertificateSerialNumber = "",
//读取的文件夹中的apiclient_key.pem文件,以-----BEGIN PRIVATE KEY-----开头、-----END PRIVATE KEY-----结尾
    MerchantCertificatePrivateKey = File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "WeChatPayConfigLibrary", "apiclient_key.pem")),
    AutoEncryptRequestSensitiveProperty = true,
    PlatformCertificateManager = manager
};
// 获取并解密平台证书
var client = new WechatTenpayClient(options);
var response = await client.ExecuteQueryCertificatesAsync(new QueryCertificatesRequest());
foreach (var certificate in response.CertificateList)
{
//其中这里会报错:
//
            //if (!certificate.Trim().StartsWith("-----BEGIN CERTIFICATE-----") || !certificate.Trim().EndsWith("-----END CERTIFICATE-----"))
               // throw new ArgumentException("The value of `certificate` is an invalid certificate file content.", nameof(certificate));
    manager.AddEntry(CertificateEntry.Parse("RSA", certificate));
}

以下是我控制器中的代码,有时候也会验签失败,不知道咋搞了大哥,

        /// <summary>
        /// HttpPost请求
        /// 接收并处理来自微信支付的回调通知
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<IActionResult> ReceiveMessage()
        {
            try
            {
                var nonce = Request.Headers["Wechatpay-Nonce"].ToString();
                var serialNumber = Request.Headers["Wechatpay-Serial"].ToString();
                var signature = Request.Headers["Wechatpay-Signature"].ToString();
                var signatureType = Request.Headers["Wechatpay-Signature-Type"].ToString();
                var timestamp = Request.Headers["Wechatpay-Timestamp"].ToString();
                using var reader = new StreamReader(Request.Body, Encoding.UTF8);
                string content = await reader.ReadToEndAsync();
                ErroredResult valid = client.VerifyEventSignature(timestamp,nonce,content,signature,serialNumber);
                if (!valid.Result)
                {
                    Log.Information("当前错误原因:{Error}", valid.Error);
                }
                var callbackModel = client.DeserializeEvent(content);
                var eventType = callbackModel.EventType?.ToUpper();
                var callbackResource = client.DecryptEventResource<SKIT.FlurlHttpClient.Wechat.TenpayV3.Events.TransactionResource>(callbackModel);
                switch (eventType)
                {
                    case "TRANSACTION.SUCCESS":
                        Log.Information("当前类型:【支付成功】");
                        break;
                    case "REFUND.SUCCESS":
                        Log.Information("当前类型:【退款成功】");
                        break;
                    default:
                        Log.Information("解析数据时发生错误");
                        break;
                }
                return StatusCode(200, new { Code = 0, IsSuccess = true, IsMessage = "请求数据成功" });

最后谢谢开发大大了!非常感谢!

Vin-Cente commented 1 month ago

问题自己已经解决,示例代码贴上:

//配置微信支付服务
var manager = new InMemoryCertificateManager();
var options = new WechatTenpayClientOptions()
{
    MerchantId = "",
    MerchantV3Secret = "",
    MerchantCertificateSerialNumber = "",
//文件放在项目根目录下的WeChatPayConfigLibrary文件夹内,自行更改
    MerchantCertificatePrivateKey = File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "WeChatPayConfigLibrary", "apiclient_key.pem")),
    PlatformCertificateManager = manager
};
// 获取并解密平台证书
var client = new WechatTenpayClient(options);
var response = await client.ExecuteQueryCertificatesAsync(new QueryCertificatesRequest() { AlgorithmType = "RSA" });
response = client.DecryptResponseSensitiveProperty(response);
foreach (var certificate in response.CertificateList)
{
    manager.AddEntry(CertificateEntry.Parse("RSA", certificate));
}
builder.Services.AddSingleton(WechatTenpayClientBuilder.Create(options).Build());

回调事件代码如下:

        /// <summary>
        /// HttpPost请求
        /// 接收并处理来自微信支付的回调通知
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<IActionResult> ReceiveMessage()
        {
            try
            {
                var nonce = Request.Headers["Wechatpay-Nonce"].ToString();
                var serialNumber = Request.Headers["Wechatpay-Serial"].ToString();
                var signature = Request.Headers["Wechatpay-Signature"].ToString();
                var signatureType = Request.Headers["Wechatpay-Signature-Type"].ToString();
                var timestamp = Request.Headers["Wechatpay-Timestamp"].ToString();
                using var reader = new StreamReader(Request.Body, Encoding.UTF8);
                string content = await reader.ReadToEndAsync();
                ErroredResult valid = client.VerifyEventSignature(timestamp,nonce,content,signature,serialNumber);
                if (!valid.Result)
                {
                    Log.Information("当前错误原因:{Error}", valid.Error);
                }
                var callbackModel = client.DeserializeEvent(content);
                var eventType = callbackModel.EventType?.ToUpper();
                var callbackResource = client.DecryptEventResource<SKIT.FlurlHttpClient.Wechat.TenpayV3.Events.TransactionResource>(callbackModel);
                switch (eventType)
                {
                    case "TRANSACTION.SUCCESS":
                        Log.Information("当前类型:【支付成功】");
                        break;
                    case "REFUND.SUCCESS":
                        Log.Information("当前类型:【退款成功】");
                        break;
                    default:
                        Log.Information("解析数据时发生错误");
                        break;
                }
                return StatusCode(200, new { Code = 0, IsSuccess = true, IsMessage = "请求数据成功" });
fudiwei commented 1 month ago

看起来已经自行解决了。这里留言给后来人提醒一下,报错是因为获取的平台证书没解密。


商户证书和平台证书的区别官方文档里有写:

https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay3_1.shtml

Vin-Cente commented 1 month ago

谢谢大哥