微信支付:C#计算签名
使用 HttpClient
来计算签名
HttpClient是.NET4.5引入的一个HTTP客户端库,其命名空间为 System.Net.Http ,.NET 4.5之前我们可能使用WebClient和HttpWebRequest来达到相同目的。HttpClient利用了最新的面向任务模式,使得处理异步请求非常容易。它适合用于多次请求操作,一般设置好默认头部后,可以进行重复多次的请求,基本上用一个实例可以提交任何的HTTP请求。HttpClient有预热机制,第一次进行访问时比较慢,所以不应该用到HttpClient就new一个出来,应该使用单例或其他方式获取HttpClient的实例
新建一个 请求处理类 HttpHandler
// 使用方法 // 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() { InnerHandler = new HttpClientHandler(); this.merchantId = ConfigData.Intance.WXPaySetting.wx_mchid; this.serialNo = ConfigData.Intance.WXPaySetting.wx_serialNo; } 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); 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(); } string uri = request.RequestUri.PathAndQuery; TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0); var timestamp = (int)ts.TotalSeconds - 28800; 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 = 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
使用:APIHelper
public class APIHelper { /// <summary> /// Native支付 统一下单 /// </summary> /// <param name="data"></param> /// <returns></returns> public async Task<Res_Native_TongYiXiaDan> Native_TongYiXiaDan(Req_Native_TongYiXiaDan data) { using (HttpClient client = GetClient()) { string url = "https://api.mch.weixin.qq.com/v3/pay/partner/transactions/native"; Newtonsoft.Json.JsonSerializerSettings settings = new Newtonsoft.Json.JsonSerializerSettings(); settings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore; string json = Newtonsoft.Json.JsonConvert.SerializeObject(data, settings); HttpContent content = new StringContent(json); content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); HttpResponseMessage response = await client.PostAsync(url, content); string responseBody = await response.Content.ReadAsStringAsync(); return Newtonsoft.Json.JsonConvert.DeserializeObject<Res_Native_TongYiXiaDan>(responseBody); } } /// <summary> /// Native支付 商户订单号查询 /// </summary> /// <param name="data"></param> /// <returns></returns> public async Task<Res_Native_DingDanChaXun> Native_ChaXunDingDan(string out_trade_no) { using (HttpClient client = GetClient()) { string url = $"https://api.mch.weixin.qq.com/v3/pay/partner/transactions/out-trade-no/{out_trade_no}?sp_mchid={Config.sp_mchid}&sub_mchid={Config.sub_mchid}"; HttpResponseMessage response = await client.GetAsync(url); string responseBody = await response.Content.ReadAsStringAsync(); return Newtonsoft.Json.JsonConvert.DeserializeObject<Res_Native_DingDanChaXun>(responseBody); } } HttpClient GetClient() { HttpClient client = new HttpClient(new HttpHandler()); // 设置 Accept client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json")); client.DefaultRequestHeaders.UserAgent.Clear(); // 设置 UserAgent var userAgent = new System.Net.Http.Headers.ProductInfoHeaderValue(new System.Net.Http.Headers.ProductHeaderValue("DataTook", "2.1.0")); client.DefaultRequestHeaders.UserAgent.Add(userAgent); return client; } }
GarsonZhang www.yesdotnet.com
HttpWebRequest
方式签名
在某些条件下,如果使用HttpClient死循环,发生在 await client.PostAsync(url, content)
处,改用 HttpWebRequest
方式请求
public class APIHelper { ConfigWXPay Config; public APIHelper() { Config = ConfigData.Intance.WXPaySetting; } /// <summary> /// Native支付 统一下单 /// </summary> /// <param name="data"></param> /// <returns></returns> public Res_Native_TongYiXiaDan Native_TongYiXiaDan(Req_Native_TongYiXiaDan data) { string url = "https://api.mch.weixin.qq.com/v3/pay/partner/transactions/native"; Newtonsoft.Json.JsonSerializerSettings settings = new Newtonsoft.Json.JsonSerializerSettings(); settings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore; string json = Newtonsoft.Json.JsonConvert.SerializeObject(data, settings); string responseBody = this.Post(url, json); return Newtonsoft.Json.JsonConvert.DeserializeObject<Res_Native_TongYiXiaDan>(responseBody); } /// <summary> /// Native支付 商户订单号查询 /// </summary> /// <param name="data"></param> /// <returns></returns> public Res_Native_DingDanChaXun Native_ChaXunDingDan(string out_trade_no) { string url = $"https://api.mch.weixin.qq.com/v3/pay/partner/transactions/out-trade-no/{out_trade_no}?sp_mchid={Config.wx_mchid}&sub_mchid={Config.wx_sub_mchid}"; string responseBody = get(url); return Newtonsoft.Json.JsonConvert.DeserializeObject<Res_Native_DingDanChaXun>(responseBody); } /// <summary> /// 客户端统一提交数据 /// </summary> /// <param name="url">WebAPI核心URL地址</param> /// <param name="param">URL参数</param> /// <returns>返回数据</returns> string get(string url) { try { System.Net.HttpWebRequest request; if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase)) { ServicePointManager.SecurityProtocol = (SecurityProtocolType)192 | (SecurityProtocolType)768 | (SecurityProtocolType)3072; ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; ServicePointManager.CheckCertificateRevocationList = false; ServicePointManager.DefaultConnectionLimit = 512; ServicePointManager.Expect100Continue = false; request = WebRequest.Create(url) as HttpWebRequest; request.ProtocolVersion = HttpVersion.Version10; request.KeepAlive = false; } else { request = (System.Net.HttpWebRequest)WebRequest.Create(url); } //request = (HttpWebRequest)WebRequest.Create(url + (param == "" ? "" : "?") + param); request.Method = "GET"; request.ContentType = "text/html;charset=UTF-8";//text/html;charset=UTF-8; request.Accept = "application/json"; request.UserAgent = "DataTook/2.1.0"; var auth = this.BuildAuthAsync(request, ""); string value = $"WECHATPAY2-SHA256-RSA2048 {auth}"; request.Headers.Add("Authorization", value); #region 获取网页内容太大的话,就加下面这两句代码 request.Headers["Accept-Encoding"] = "gzip,deflate"; request.AutomaticDecompression = DecompressionMethods.GZip; #endregion request.Timeout = WebApiTools.TimeOut; HttpWebResponse response = (HttpWebResponse)request.GetResponse(); Stream myResponseStream = response.GetResponseStream(); StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8")); string retString = myStreamReader.ReadToEnd(); myStreamReader.Close(); myResponseStream.Close(); return retString; } catch (WebException ex) { string result = "GET:操作失败!\r\n" + ex.Message; if (ex.Response != null) result = result + "\r\n" + GetResponseText(ex.Response); throw new Exception(result); } catch (Exception ex) { throw new Exception("GET:操作失败!\r\n" + ex.Message); } } /// <summary> /// 客户端统一提交数据 /// </summary> /// <param name="url">WebAPI核心URL地址</param> /// <param name="data">提交的数据</param> /// <returns>返回数据</returns> string Post(string url, string data) { string returnData = null; try { string strURL = url; System.Net.HttpWebRequest request; if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase)) { ServicePointManager.SecurityProtocol = (SecurityProtocolType)192 | (SecurityProtocolType)768 | (SecurityProtocolType)3072; ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; ServicePointManager.CheckCertificateRevocationList = false; ServicePointManager.DefaultConnectionLimit = 512; ServicePointManager.Expect100Continue = false; request = WebRequest.Create(url) as HttpWebRequest; request.ProtocolVersion = HttpVersion.Version10; request.KeepAlive = false; } else { request = (System.Net.HttpWebRequest)WebRequest.Create(strURL); } request.Method = "POST"; request.ContentType = "application/json";// "application/json;charset=UTF-8";//POST必须使用JSON格式 request.Accept = "application/json"; request.UserAgent = "DataTook/2.1.0"; var auth = this.BuildAuthAsync(request, data); string value = $"WECHATPAY2-SHA256-RSA2048 {auth}"; request.Headers.Add("Authorization", value); string paraUrlCoded = data; byte[] payload; payload = System.Text.Encoding.UTF8.GetBytes(paraUrlCoded); request.ContentLength = payload.Length; request.Timeout = WebApiTools.TimeOut; Stream writer = request.GetRequestStream(); writer.Write(payload, 0, payload.Length); writer.Close(); System.Net.HttpWebResponse response; response = (System.Net.HttpWebResponse)request.GetResponse(); System.IO.Stream s; s = response.GetResponseStream(); string StrDate = ""; string strValue = ""; StreamReader Reader = new StreamReader(s, Encoding.GetEncoding("utf-8")); while ((StrDate = Reader.ReadLine()) != null) { strValue += StrDate + "\r\n"; } returnData = strValue; return returnData.Trim() + "\n"; } catch (WebException ex) { string result = "POST:操作失败!\r\n" + ex.Message; if (ex.Response != null) result = result + "\r\n" + GetResponseText(ex.Response); throw new Exception(result); } catch (Exception ex) { throw new Exception("POST:操作失败!\r\n" + ex.Message); } } protected string BuildAuthAsync(HttpWebRequest request, string body) { string merchantId = ConfigData.Intance.WXPaySetting.wx_mchid; string serialNo = ConfigData.Intance.WXPaySetting.wx_serialNo; string method = request.Method.ToString(); string uri = request.RequestUri.PathAndQuery; TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0); var timestamp = (int)ts.TotalSeconds - 28800; 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 = 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())); } private static string GetResponseText(WebResponse response) { string text; using (StreamReader sr = new StreamReader(response.GetResponseStream())) { text = sr.ReadToEnd(); } if ((response is HttpWebResponse)) { int status = (int)(response as HttpWebResponse).StatusCode; if (status == 429) text = "流量访问限制!" + text; } return text; } }
GarsonZhang www.yesdotnet.com
版权声明:本文为YES开发框架网发布内容,转载请附上原文出处连接
OnlinePay 管理员