ASP.NET Core 微信支付(一)【統一下單 APIV3】


官方參考資料

簽名:https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_0.shtml

簽名生成:https://wechatpay-api.gitbook.io/wechatpay-api-v3/qian-ming-zhi-nan-1/qian-ming-sheng-cheng

統一下單接口:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_2_1.shtml

如何查看證書序列號:https://wechatpay-api.gitbook.io/wechatpay-api-v3/chang-jian-wen-ti/zheng-shu-xiang-guan#ru-he-cha-kan-zheng-shu-xu-lie-hao

私鑰和證書:https://wechatpay-api.gitbook.io/wechatpay-api-v3/ren-zheng/zheng-shu#sheng-ming-suo-shi-yong-de-zheng-shu

 

首先聲明,我這個是為APP支付提供的接口!!!其他端使用時僅供參考!!

 

本地調試時記得安裝微信支付安全證書!!!發布到服務器上也要安裝微信支付安全證書!!!

 

私鑰從微信支付后台發放的證書中拷貝出來!!!!!

 

  一、簽名

    生成簽名

參考資料里面講的比較詳細,也有官方的文檔,不過文檔不全,導致我的調試程序一直出現問題,請求微信的統一下單接口總是報400錯誤(Bad Request)。

簽名生成參考官方代碼,代碼如下,里面有我標注的請求接口報400錯誤原因的代碼

using System;
using System.IO;
using System.Net.Http;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;

namespace HttpHandlerDemo
{
    // 使用方法
    // HttpClient client = new HttpClient(new HttpHandler("{商戶號}", "{商戶證書序列號}"));
    // ...
    // var response = client.GetAsync("https://api.mch.weixin.qq.com/v3/certificates");
    public class HttpHandler : DelegatingHandler
    {
        private readonly string merchantId;
        private readonly string serialNo;

        public HttpHandler(string merchantId, string merchantSerialNo)
        {
            InnerHandler = new HttpClientHandler();

            this.merchantId = merchantId;
            this.serialNo = merchantSerialNo;
        }

        protected async override Task<HttpResponseMessage> SendAsync(
            HttpRequestMessage request,
            CancellationToken cancellationToken)
        {
            var auth = await BuildAuthAsync(request);
            string value = $"WECHATPAY2-SHA256-RSA2048 {auth}";
            request.Headers.Add("Authorization", value);
            request.Headers.Add("Accept", "application/json");//如果缺少這句代碼就會導致下單接口請求失敗,報400錯誤(Bad Request)
            request.Headers.Add("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)");//如果缺少這句代碼就會導致下單接口請求失敗,報400錯誤(Bad Request)

            return await base.SendAsync(request, cancellationToken);
        }

        protected async Task<string> BuildAuthAsync(HttpRequestMessage request)
        {
            string method = request.Method.ToString();
            string body = "";
            if (method == "POST" || method == "PUT" || method == "PATCH")
            {
                var content = request.Content;
                body = await content.ReadAsStringAsync();//debug的時候在這里打個斷點,看看body的值是多少,如果跟你傳入的參數不一致,說明是有問題的,一定參考我的方法
            }

            string uri = request.RequestUri.PathAndQuery;
            var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
            string nonce = Path.GetRandomFileName();

            string message = $"{method}\n{uri}\n{timestamp}\n{nonce}\n{body}\n";
            string signature = Sign(message);
            return $"mchid=\"{merchantId}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{serialNo}\",signature=\"{signature}\"";
        }

        protected string Sign(string message)
        {
            // NOTE: 私鑰不包括私鑰文件起始的-----BEGIN PRIVATE KEY-----
            //        亦不包括結尾的-----END PRIVATE KEY-----
            string privateKey = "{你的私鑰}";
            byte[] keyData = Convert.FromBase64String(privateKey);
            using (CngKey cngKey = CngKey.Import(keyData, CngKeyBlobFormat.Pkcs8PrivateBlob))
            using (RSACng rsa = new RSACng(cngKey))
            {
                byte[] data = System.Text.Encoding.UTF8.GetBytes(message);
                return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
            }
        }
    }
}

  二、統一下單

    使用方法

 var url = "https://api.mch.weixin.qq.com/v3/pay/transactions/app";
 var req = new GenerateOrderModelForWxPay
                {
                    appid = WxPayConst.appid,
                    mchid = WxPayConst.mchid,
                    description = "商品名稱",
                    amount = new WxPayAmountModel
                    {
                        total = 1
                    },
                    out_trade_no = orderNumber,
                    notify_url = "https://xxx.com/api/WxPayCallback"
                };
HttpClient client = new HttpClient(new HttpHandler("{商戶號}", "{商戶證書序列號}"));
//GET 方式
var response = client.GetAsync("https://api.mch.weixin.qq.com/v3/certificates");

// POST 方式
 var bodyJson = new StringContent(req.ToJson(), Encoding.UTF8, "application/json"); //一定要這樣傳遞參數,不然在加密簽名的時候獲取到的參數就是\\u0這種形式的數據了,不是傳遞的這樣的數據了,導致加密的結果不正確
var response = await client.PostAsync(url, bodyJson);

// 讀取統一下單之后的返回結果,這樣讀取出來的直接就是結果,或者錯誤原因,大家一定要這么搞啊!!!多么痛的領悟,會有具體的錯誤信息的。
var respStr = await response.Content.ReadAsStringAsync();//這里面就包含prepay_id了

 三、注意

  大家一定看接口規則里面的說明,我就是沒有看,導致我搞了一天沒有搞通,下面貼兩個截圖

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM