首先,我要吐槽一下微信这些人办事的态度,真是不负责任,之前的【商家付款到零钱】用的好好的,强制换成这个东西,换了就换了吧,你把文档弄完善好吗,文档写的含糊不清,有些地方的链接点进去居然还是V2的东西,甚至404,我只能说呵呵了。
话不多说,直接贴代码:
/// <summary> /// 获取authorzation 值 /// </summary> /// <param name="url">微信的接口地址</param> /// <param name="method">请求的方式GET,POST,PUT</param> /// <param name="jsonParame">post请求的数据,json格式 ,get时传空</param> /// <param name="privateKey">apiclient_key.pem中的内容,不要-----BEGIN PRIVATE KEY----- -----END PRIVATE KEY-----</param> /// <param name="merchantId">发起请求的商户(包括直连商户、服务商或渠道商)的商户号 mchid</param> /// <param name="serialNo">商户证书号</param> /// <returns></returns> protected string GetAuthorization(string url, string method, string jsonParame, string merchantId, string serialNo) { var uri = new Uri(url); string urlPath = uri.PathAndQuery; string nonce = Guid.NewGuid().ToString(); var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds(); //数据签名 HTTP请求方法n接口地址的urln请求时间戳n请求随机串n请求报文主体n method = string.IsNullOrEmpty(method) ? "" : method; string message = $"{method}\n{urlPath}\n{timestamp}\n{nonce}\n{jsonParame}\n"; string signTxt = Sign(message); //Authorization和格式 string authorzationTxt = $"mchid=\"{merchantId}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{serialNo}\",signature=\"{signTxt}\""; ; return authorzationTxt; } /// <summary> /// V3版本请求接口 /// </summary> /// <param name="url">微信的接口地址</param> /// <param name="postData">post请求的数据,json格式 </param> /// <param name="privateKey">apiclient_key.pem中的内容,不要-----BEGIN PRIVATE KEY----- -----END PRIVATE KEY-----</param> /// <param name="merchantId">发起请求的商户(包括直连商户、服务商或渠道商)的商户号 mchid</param> /// <param name="serialNo">商户证书号</param> /// <param name="method"></param> /// <returns></returns> public string WxV3PostJson(string url, string postData, string merchantId, string serialNo, string method, string wxserial_no) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Method = method; request.ContentType = "application/json;charset=UTF-8"; request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3100.0 Safari/537.36"; request.Accept = "application/json"; string Authorization = GetAuthorization(url, method, postData, merchantId, serialNo); string value = $"WECHATPAY2-SHA256-RSA2048 {Authorization}"; request.Headers.Add("Authorization", value); if (!string.IsNullOrEmpty(wxserial_no)) { request.Headers.Add("Wechatpay-Serial", wxserial_no); } if (!string.IsNullOrEmpty(postData)) { byte[] paramJsonBytes; paramJsonBytes = System.Text.Encoding.UTF8.GetBytes(postData); request.ContentLength = paramJsonBytes.Length; Stream writer; try { writer = request.GetRequestStream(); } catch (Exception e) { writer = null; _log.Info("请求接口失败:" + e.Message); } writer.Write(paramJsonBytes, 0, paramJsonBytes.Length); writer.Close(); } HttpWebResponse response; try { response = (HttpWebResponse)request.GetResponse(); } catch (WebException ex) { response = ex.Response as HttpWebResponse; } Stream resStream = response.GetResponseStream(); StreamReader reader = new StreamReader(resStream); string text = reader.ReadToEnd(); return text; } /// <summary> /// 获取签名 /// </summary> protected string Sign(string message) { //加载证书 _apiCertPath API证书物理路径 _certPwd API证书密码(默认是商户号) string path = MyServiceProvider.ServiceProvider.GetRequiredService<IHostEnvironment>().ContentRootPath; X509Certificate2 cer = new X509Certificate2(path + SSLCERT_PATH, _settings.mchild, X509KeyStorageFlags.Exportable); if (cer != null) { RSA rsa = cer.GetRSAPrivateKey(); //获取私钥 //查看在不同平台上的具体类型 byte[] data = Encoding.UTF8.GetBytes(message); return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)); } else { return ""; } } public static string RSAEncrypt(string text, byte[] publicKey) { try { using (var x509 = new X509Certificate2(publicKey)) { var rsaParam = x509.GetRSAPublicKey().ExportParameters(false); var rsa = new RSACryptoServiceProvider(); rsa.ImportParameters(rsaParam); var buff = rsa.Encrypt(Encoding.UTF8.GetBytes(text), true); return Convert.ToBase64String(buff); } } catch (Exception ex) { throw; } } [HttpPost] /// <summary> /// 商家转账到零钱 /// </summary> /// <param name="dto"></param> /// <returns></returns> public async Task<ResultObj> WithDrawsToWx(PayReq dto) { try { var body = new { appid = _settings.wxmp_appid, out_batch_no = dto.out_batch_no, batch_name = dto.batch_name, batch_remark = dto.batch_remark, total_amount = dto.total_amount, total_num = dto.total_num, transfer_scene_id = dto.transfer_scene_id, transfer_detail_list = dto.transfer_detail_list }; string Authorization2 = GetAuthorization2("/v3/certificates", "GET", _settings.mchild, _settings.api_serialNo); certificates certificate = JsonConvert.DeserializeObject<certificates>(Authorization2); if (certificate.data.Count == 0) { _log.Info("获取支付平台证书序列号的时候出错了"); } string publickey = AesGcmHelper.AesGcmDecrypt(certificate.data[0].encrypt_certificate.associated_data, certificate.data[0].encrypt_certificate.nonce, certificate.data[0].encrypt_certificate.ciphertext); foreach (Transfer_Detail_Item item in dto.transfer_detail_list) { item.user_name = RSAEncrypt(item.user_name, Encoding.Default.GetBytes(publickey)); } var url = "https://api.mch.weixin.qq.com/v3/transfer/batches"; string transactionsResponse = WxV3PostJson(url, JsonConvert.SerializeObject(body), _settings.mchild, _settings.api_serialNo, "POST", certificate.data[0].serial_no); //_log.LogInformation("商户转账到零钱返回:" + transactionsResponse); //WithDrawsV3Back result =JsonConvert.DeserializeObject<WithDrawsV3Back>(transactionsResponse); return ResultObj.WebSuccess(transactionsResponse); } catch (Exception ex) { return ResultObj.WebSuccess(ex.Message); throw; } }