评论

开源微信支付 v3 版 .Net SDK(支持 .NET Core / Framework,完整封装全部 v3 API)

.NET Core & Framework 微信支付 v3 版 API SDK,可跨平台,支持直连商户 & 服务商,请求自动签名,提供 RSA、AES-GCM、SHA-256 工具类。

基于 Flurl.Http 的微信支付 API v3 版 .NET SDK。

注意:本库仅支持 v3 版 API,如需 v2 版 API 请移步 SKIT.FlurlHttpClient.Wechat.TenpayV2

GitHub 项目地址:https://github.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat

Gitee 项目地址:https://gitee.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat

NuGet 项目地址:https://www.nuget.org/packages/SKIT.FlurlHttpClient.Wechat.TenpayV3


前言

目前网络上还没有基于微信支付 v3 版 API 完整封装的 .NET 客户端(大部分只提供了基础的如支付、退款一类 API 封装),遑论开源了;这都 2021 年了,官方本身提供的示例代码还只能运行在 .NET Framework on Windows 上;就连 RSA 签名这么基础的东西都没有人封装(确切的说是因为 RSA 有很多种分块模式和填充模式,网上能找到的往往只封装了其中一种,但却未必符合微信支付的要求)。

于是萌生了自己封装一个库的想法,打算解决这几个痛点,同时也是推广一下微软官方的 System.Text.Json


特性

  • 基于 Flurl.Http,可与 IHttpClientFactory 集成。
  • 支持 .NET Framework 4.6.1+、.NET Standard 2.0+、.NET Core 2.0+、.NET 5、.NET 6。
  • 支持 Windows / Linux / macOS 多平台部署。
  • 支持 System.Text.Json(默认)和 Newtonsoft.Json 两种序列化方式。
  • 异步式编程。
  • 强类型接口模型。
  • 支持拦截器功能。
  • 完整、完善、完全的微信支付 API 封装,支持目前(截至 2021-12-01)微信支付提供的全部 v3 版 API
  • 支持直连商户服务商两种模式。
  • 请求时自动生成签名,无需开发者手动干预。
  • 提供了微信支付所需的 RSAAESSHA-256 等算法工具类。
  • 提供 SourceLink,方便项目无源码调试。
  • 提供了生成 JS-SDK/APP 调起支付参数及签名加密请求敏感数据解析响应敏感数据解析回调通知事件敏感数据等扩展方法。

基础用法

安装:

# 通过 NuGet 安装
> Install-Package SKIT.FlurlHttpClient.Wechat.TenpayV3

# 通过 dotnet-tools 安装
> dotnet add package SKIT.FlurlHttpClient.Wechat.TenpayV3

你也可通过 Visual Studio NuGet 管理器图形化界面安装(注意搜索时需勾选“包括预发行版”)。

初始化:

using SKIT.FlurlHttpClient.Wechat;
using SKIT.FlurlHttpClient.Wechat.TenpayV3;

/* 平台证书管理器,具体用法请参见文档的高级技巧 */
var manager = new InMemoryCertificateManager();
/* 仅列出必须配置项。也包含一些诸如超时时间、UserAgent 等的配置项 */
var options = new WechatTenpayClientOptions()
{
    MerchantId = "微信商户号",
    MerchantV3Secret = "微信商户 v3 API 密钥",
    MerchantCertificateSerialNumber = "微信商户证书序列号",
    MerchantCertificatePrivateKey = "-----BEGIN PRIVATE KEY-----微信商户证书私钥-----END PRIVATE KEY-----",
    PlatformCertificateManager = manager
};
var client = new WechatTenpayClient(options);

请求 & 响应:

using SKIT.FlurlHttpClient.Wechat.TenpayV3;
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Models;

/* 以 JSAPI 统一下单接口为例 */
var request = new CreatePayTransactionJsapiRequest()
{
    OutTradeNumber = "商户订单号",
    AppId = "微信 AppId",
    Description = "订单描述",
    ExpireTime = DateTimeOffset.Now.AddMinutes(15),
    NotifyUrl = "https://example.com",
    Amount = new Models.CreatePayTransactionJsapiRequest.Types.Amount()
    {
        Total = 100
    },
    Payer = new Models.CreatePayTransactionJsapiRequest.Types.Payer()
    {
        OpenId = "用户 OpenId"
    }
};
var response = await client.ExecuteCreatePayTransactionJsapiAsync(request);
if (response.IsSuccessful())
{
    Console.WriteLine("PrepayId:" + response.PrepayId);
}
else
{
    Console.WriteLine("HTTP 状态:" + response.RawStatus);
    Console.WriteLine("错误代码:" + response.ErrorCode);
    Console.WriteLine("错误描述:" + response.ErrorMessage);
}

验证响应签名:

/* 一般情况下可以跳过验证响应的签名 */
bool valid = client.VerifyResponseSignature(response);

生成客户端 JS-SDK 调起支付所需参数:

/* 字典结构,包含客户端 JS-SDK 调起支付所需的完整参数 */
var paramMap = client.GenerateParametersForJsapiPayRequest(request.AppId, response.PrepayId);

验签、解析并解密微信回调通知中的敏感信息:

string callbackJson = "{ 微信商户平台发来的 JSON 格式的通知内容 }";
string callbackTimestamp = "微信回调通知中的 Wechatpay-Timestamp 标头";
string callbackNonce = "微信回调通知中的 Wechatpay-Nonce 标头";
string callbackSignature = "微信回调通知中的 Wechatpay-Signature 标头";
string callbackSerialNumber = "微信回调通知中的 Wechatpay-Serial 标头";
 
bool valid = client.VerifyEventSignature(callbackTimestamp, callbackNonce, callbackJson, callbackSignature, callbackSerialNumber);
if (valid)
{
    /* 将 JSON 反序列化得到通知对象 */
    /* 你也可以将 WechatTenpayEvent 类型直接绑定到 MVC 模型上,这样就不再需要手动反序列化 */
    var callbackModel = client.DeserializeEvent(callbackJson);
    if ("TRANSACTION.SUCCESS".Equals(callbackModel.EventType))
    {
        /* 根据事件类型,解密得到支付通知敏感数据 */
        var callbackResource = client.DecryptEventResource<Events.TransactionResource>(callbackModel);
        string outTradeNumber = callbackResource.OutTradeNumber;
        string transactionId = callbackResource.TransactionId;
        Console.WriteLine("订单 {0} 已完成支付,交易单号为 {1}", outTradeNumber, transactionId);
    }
}

更多使用说明请阅读项目仓库中的开发文档。

项目仓库中还包含了一个示例项目,以供开发者快速掌握本库的使用方法。


高级技巧

点此查看完整文档

最后一次编辑于  2022-07-21  
点赞 11
收藏
评论

16 个评论

  • intrain
    intrain
    2022-08-21

    支付成功返回接口,解密时总是出现平台证书序列号不对,在client的预设里,用了商户支付证书序列号和平台证书序列号都不对,这时里要配置什么值?

    查了资料,也申请了平台证书文件:

    可不知道怎么引入到这里,求解

    2022-08-21
    赞同
    回复 2
    • puxu88
      puxu88
      2023-03-31
      证书管理添加 把平台下载的证书也读进去
      2023-03-31
      回复
    • puxu88
      puxu88
      2023-03-31
      2023-03-31
      回复
  • 时间你好慢
    时间你好慢
    2022-07-15

    感谢,使用您的SDK解决了解密问题

    2022-07-15
    赞同
    回复
  • 周国金
    周国金
    2022-03-12

    ExecuteCreatePayTransactionH5Async里,scene_info设置貌似不正确

    2022-03-12
    赞同
    回复
  • 啊哈!
    啊哈!
    2022-02-15

    调用 ExecuteCreatePayTransactionJsapiAsync 返回 受理机构必须传入sub_mch_id

    2022-02-15
    赞同
    回复
  • Vicky陈_
    Vicky陈_
    2021-10-24

    没有商户平台的退款接口,只有服务商的

    2021-10-24
    赞同
    回复 2
    • ㅤㅤㅤㅤ
      ㅤㅤㅤㅤ
      2021-10-27
      有的,这俩是同一个接口,传不同的参数而已
      2021-10-27
      回复
    • Vicky陈_
      Vicky陈_
      2021-12-13回复ㅤㅤㅤㅤ
      商户后台退款的回调是xml,你们的sdk不能解析xml?
      2021-12-13
      回复
  • 网神
    网神
    2021-08-19

    能发一套服务商的例子吗

    2021-08-19
    赞同
    回复 2
    • ㅤㅤㅤㅤ
      ㅤㅤㅤㅤ
      2021-08-19
      仓库里有详细文档哈~
      2021-08-19
      回复
    • 手可摘星辰
      手可摘星辰
      2023-01-01回复ㅤㅤㅤㅤ
      请问下下单为什么总是报签名错误用自己写的也是
      2023-01-01
      回复

正在加载...

登录 后发表内容