微信支付:签名计算.net4.5


微信支付 签名 计算在.net4.5中无法使用,.net 4.5环境中生成微信支付的 签名

官方的 签名 计算方法 微信支付-签名生成 

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 SendAsync(
            HttpRequestMessage request,
            CancellationToken cancellationToken)
        {
            var auth = await BuildAuthAsync(request);
            string value = $"WECHATPAY2-SHA256-RSA2048 {auth}";
            request.Headers.Add("Authorization", value);

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

        protected async Task 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();
            }

            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));
            }
        }
    }
}
GarsonZhang www.yesdotnet.com

这份代码中使用了 RSACng 类,

这个类适用范围 RSACng 类 (System.Security.Cryptography) | Microsoft Docs

适用于
产品版本
.NET5.0, 6.0 Preview 3
.NET Core1.0, 1.1, 3.0, 3.1
.NET Framework4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8
.NET Platform Extensions2.1, 2.2, 3.0, 3.1, 5.0, 6.0 Preview 3
Xamarin.Android7.1
Xamarin.iOS10.8
Xamarin.Mac3.0

如果你是.net4.5环境, RSACng 类无法使用,签名 计算 sign 方法就会报错

Sign 方法需要修改为

protected string Sign(string message)
{
    // NOTE: 私钥不包括私钥文件起始的-----BEGIN PRIVATE KEY-----
    //        亦不包括结尾的-----END PRIVATE KEY-----
    string privateKey = ConfigData.Intance.WXPaySetting.wx_private_key;


    //转换成适用于.Net的秘钥
    var netKey = RSAPrivateKeyJava2DotNet(privateKey);
    var rsa = new RSACryptoServiceProvider();
    rsa.FromXmlString(netKey);
    //创建一个空对象
    var rsaClear = new RSACryptoServiceProvider();
    var paras = rsa.ExportParameters(true);
    rsaClear.ImportParameters(paras);
    //签名返回
    using (var sha256 = new SHA256CryptoServiceProvider())
    {
        var signData = rsa.SignData(Encoding.UTF8.GetBytes(message), sha256);
        string s2 = Convert.ToBase64String(signData);
        return s2;
    }
}

string RSAPrivateKeyJava2DotNet(string privateKey)
{
    RsaPrivateCrtKeyParameters privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKey));

    return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent><P>{2}</P><Q>{3}</Q><DP>{4}</DP><DQ>{5}</DQ><InverseQ>{6}</InverseQ><D>{7}</D></RSAKeyValue>",
        Convert.ToBase64String(privateKeyParam.Modulus.ToByteArrayUnsigned()),
        Convert.ToBase64String(privateKeyParam.PublicExponent.ToByteArrayUnsigned()),
        Convert.ToBase64String(privateKeyParam.P.ToByteArrayUnsigned()),
        Convert.ToBase64String(privateKeyParam.Q.ToByteArrayUnsigned()),
        Convert.ToBase64String(privateKeyParam.DP.ToByteArrayUnsigned()),
        Convert.ToBase64String(privateKeyParam.DQ.ToByteArrayUnsigned()),
        Convert.ToBase64String(privateKeyParam.QInv.ToByteArrayUnsigned()),
        Convert.ToBase64String(privateKeyParam.Exponent.ToByteArrayUnsigned()));
}
GarsonZhang www.yesdotnet.com

 

版权声明:本文为YES开发框架网发布内容,转载请附上原文出处连接
管理员
评论列表

发表评论

评论内容
昵称:
关联文章

支付签名计算.net4.5
支付:C#计算签名
支付签名计算.net4.5
【已解决】.NET 支付API V3中JSAPI支付发起wx.chooseWXPay时,提示 支付验证签名失败
支付接口签名校验工具
支付: API V3支付回调签名验证
Asp.net H5唤起支付支付回调
支付:C#计算签名
/支付宝 在线支付测试工具
支付:JSAPI支付 开发手册
支付支付成功没有回调通知Notify_URL
支付官方相关工具下载
支付:header中的mchid与post payload中的mchid不匹配
支付:API v3 Postman脚本使用指南
支付:Http头缺少Accept或User-Agent
支付,当面付,开发手册
JS 接口签名校验工具 (qq.com)
支付接口签名校验工具
支付:受理机构必须传入sub_mch_id
支付:商户API私钥