WeChatFunction.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. using System;
  2. using System.Collections.Generic;
  3. using Library;
  4. using System.Security.Cryptography.X509Certificates;
  5. using System.Security.Cryptography;
  6. using Microsoft.AspNetCore.Http;
  7. using System.Text;
  8. using System.IO;
  9. using System.Linq;
  10. using MySystem;
  11. using LitJson;
  12. using System.Net;
  13. using Org.BouncyCastle.Crypto.Modes;
  14. using Org.BouncyCastle.Crypto.Parameters;
  15. using Org.BouncyCastle.Crypto.Engines;
  16. namespace MySystem
  17. {
  18. public class WeChatFunction
  19. {
  20. private HttpContext _context;
  21. public WeChatFunction(HttpContext context)
  22. {
  23. _context = context;
  24. }
  25. #region 领取会员卡
  26. public Dictionary<string, object> GetUserCard(int MerchantId)
  27. {
  28. string token = new WeChat.WeChatPublicClass(_context).getWXToken("wx5417e0770bb19c4e", "b853caabd367e1f3fd729c259ac8bee6");
  29. string resp = function.GetWebRequest("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + token + "&type=wx_card");
  30. JsonData jsonObj = JsonMapper.ToObject(resp);
  31. string ticket = jsonObj["ticket"].ToString();
  32. string timeStamp = function.ConvertDateTimeInt(DateTime.Now).ToString();
  33. string nonce_str = function.get_Random(12);
  34. var pay_param = new SortedList<string, string>
  35. {
  36. {"timeStamp", timeStamp},
  37. {"nonceStr", nonce_str},
  38. {"ticket", ticket}
  39. };
  40. var pay_param_str = String.Join("&", pay_param.Select(item => String.Format("{0}={1}", item.Key.Trim(), item.Value)).ToArray());
  41. string signature = new WeChat.WeChatPublicClass(_context).SHA1(pay_param_str);
  42. Dictionary<string, object> cardExt = new Dictionary<string, object>();
  43. cardExt.Add("timestamp", timeStamp);
  44. cardExt.Add("nonce_str", nonce_str);
  45. cardExt.Add("signature", signature);
  46. return cardExt;
  47. }
  48. #endregion
  49. #region 服务商平台JSAPI下单
  50. public Dictionary<string, string> Pay(string AppId, string MchId, string SubMchId, decimal PayMoney, string OrderNo, string Description, string OpenId, string Key, string NotifyUrl)
  51. {
  52. Dictionary<string, string> return_result = new Dictionary<string, string>();
  53. int amount = (int)(PayMoney * 100);
  54. //具体请求参数
  55. SortedList<string, object> par = new SortedList<string, object>();
  56. par.Add("sp_appid", AppId); //服务商应用ID
  57. par.Add("sp_mchid", MchId); //服务商户号
  58. par.Add("sub_mchid", SubMchId); //子商户号
  59. par.Add("description", Description); //商品描述
  60. par.Add("out_trade_no", OrderNo); //商户订单号
  61. par.Add("notify_url", NotifyUrl); //服务商应用ID
  62. Dictionary<string, object> amountDic = new Dictionary<string, object>();
  63. amountDic.Add("total", amount); //总金额
  64. par.Add("amount", amountDic); //订单金额
  65. Dictionary<string, object> payer = new Dictionary<string, object>();
  66. payer.Add("sp_openid", OpenId); //用户在服务商appid下的唯一标识
  67. par.Add("payer", payer); //支付者
  68. string req = Newtonsoft.Json.JsonConvert.SerializeObject(par);
  69. function.WriteLog(req, "服务商平台JSAPI下单请求参数");
  70. try
  71. {
  72. string merchantId = MchId; //商户号
  73. string serialNo = "62B64854B768D344249FDB9E6EF4A1232C000E84"; //证书编号
  74. function.WriteLog(serialNo, "服务商平台JSAPI下单请求参数");
  75. function.WriteLog(Newtonsoft.Json.JsonConvert.SerializeObject(par), "服务商平台JSAPI下单请求参数");
  76. string result = postJson("https://api.mch.weixin.qq.com/v3/pay/partner/transactions/jsapi", req, prikey, merchantId, serialNo);
  77. function.WriteLog(result, "服务商平台JSAPI下单请求参数");
  78. JsonData jsonObj = JsonMapper.ToObject(result);
  79. string timeStamp = function.ConvertDateTimeInt(DateTime.Now).ToString();
  80. string nonce_str = function.get_Random(12);
  81. string package = "prepay_id=" + jsonObj["prepay_id"].ToString();
  82. var pay_param = new SortedList<string, string>
  83. {
  84. {"appId", AppId},
  85. {"timeStamp", timeStamp},
  86. {"nonceStr", nonce_str},
  87. {"package", package},
  88. {"signType", "RSA"}
  89. };
  90. var pay_param_str = "";
  91. pay_param_str += AppId + "\n";
  92. pay_param_str += timeStamp + "\n";
  93. pay_param_str += nonce_str + "\n";
  94. pay_param_str += package + "\n";
  95. string paySign = Sign(pay_param_str, prikey);
  96. return_result.Add("appId", AppId);
  97. return_result.Add("timeStamp", timeStamp);
  98. return_result.Add("nonceStr", nonce_str);
  99. return_result.Add("package", package);
  100. return_result.Add("paySign", paySign);
  101. }
  102. catch (Exception ex)
  103. {
  104. function.WriteLog(DateTime.Now.ToString() + "\r\n" + ex.ToString(), "服务商品台JSAPI下单异常");
  105. }
  106. return return_result;
  107. }
  108. #endregion
  109. #region 服务商平台申请退款API
  110. public Dictionary<string, string> Refund(string AppId, string MchId, string SubMchId, decimal RefundMoney, decimal TotalMoney, string OrderNo, string RefundNo, string Description, string OpenId, string Key, string NotifyUrl)
  111. {
  112. Dictionary<string, string> return_result = new Dictionary<string, string>();
  113. int refund = (int)(RefundMoney * 100);
  114. int amount = (int)(TotalMoney * 100);
  115. //具体请求参数
  116. SortedList<string, object> par = new SortedList<string, object>();
  117. par.Add("sub_mchid", SubMchId); //子商户号
  118. par.Add("out_trade_no", OrderNo); //商户订单号
  119. par.Add("out_refund_no", RefundNo); //商户退款单号
  120. Dictionary<string, object> amountDic = new Dictionary<string, object>();
  121. amountDic.Add("refund", refund); //退款金额
  122. amountDic.Add("total", amount); //原订单金额
  123. amountDic.Add("currency", "CNY"); //退款币种
  124. par.Add("amount", amountDic); //金额信息
  125. string req = Newtonsoft.Json.JsonConvert.SerializeObject(par);
  126. function.WriteLog(req, "服务商平台申请退款API");
  127. try
  128. {
  129. string merchantId = MchId; //商户号
  130. string serialNo = "62B64854B768D344249FDB9E6EF4A1232C000E84"; //证书编号
  131. string result = postJson("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds", req, prikey, merchantId, serialNo);
  132. function.WriteLog(result, "服务商平台申请退款API");
  133. JsonData jsonObj = JsonMapper.ToObject(result);
  134. return_result.Add("refund_id", jsonObj["refund_id"].ToString()); //微信支付退款单号
  135. return_result.Add("channel", jsonObj["channel"].ToString()); //退款渠道
  136. return_result.Add("user_received_account", jsonObj["user_received_account"].ToString()); //退款入账账户
  137. return_result.Add("status", jsonObj["status"].ToString()); //退款状态
  138. return_result.Add("payer_total", jsonObj["amount"]["payer_total"].ToString()); //用户支付金额
  139. return_result.Add("payer_refund", jsonObj["amount"]["payer_refund"].ToString()); //用户退款金额
  140. return_result.Add("settlement_refund", jsonObj["amount"]["settlement_refund"].ToString()); //应结退款金额
  141. return_result.Add("settlement_total", jsonObj["amount"]["settlement_total"].ToString()); //应结订单金额
  142. return_result.Add("discount_refund", jsonObj["amount"]["discount_refund"].ToString()); //优惠退款金额
  143. }
  144. catch (Exception ex)
  145. {
  146. function.WriteLog(DateTime.Now.ToString() + "\r\n" + ex.ToString(), "服务商平台申请退款API异常");
  147. }
  148. return return_result;
  149. }
  150. #endregion
  151. #region 服务商平台查询单笔退款API
  152. public Dictionary<string, string> QueryRefund(string RefundNo)
  153. {
  154. Dictionary<string, string> return_result = new Dictionary<string, string>();
  155. try
  156. {
  157. string result = function.GetWebRequest("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/" + RefundNo);
  158. JsonData jsonObj = JsonMapper.ToObject(result);
  159. return_result.Add("refund_id", jsonObj["refund_id"].ToString()); //微信支付退款单号
  160. return_result.Add("transaction_id", jsonObj["transaction_id"].ToString()); //微信支付订单号
  161. return_result.Add("out_trade_no", jsonObj["out_trade_no"].ToString()); //商户订单号
  162. return_result.Add("channel", jsonObj["channel"].ToString()); //退款渠道
  163. return_result.Add("user_received_account", jsonObj["user_received_account"].ToString()); //退款入账账户
  164. return_result.Add("status", jsonObj["status"].ToString()); //退款状态
  165. return_result.Add("total", jsonObj["amount"]["total"].ToString()); //订单金额
  166. return_result.Add("refund", jsonObj["amount"]["refund"].ToString()); //退款金额
  167. return_result.Add("payer_total", jsonObj["amount"]["payer_total"].ToString()); //用户支付金额
  168. return_result.Add("payer_refund", jsonObj["amount"]["payer_refund"].ToString()); //用户退款金额
  169. return_result.Add("settlement_refund", jsonObj["amount"]["settlement_refund"].ToString()); //应结退款金额
  170. return_result.Add("settlement_total", jsonObj["amount"]["settlement_total"].ToString()); //应结订单金额
  171. return_result.Add("discount_refund", jsonObj["amount"]["discount_refund"].ToString()); //优惠退款金额
  172. }
  173. catch (Exception ex)
  174. {
  175. function.WriteLog(DateTime.Now.ToString() + "\r\n" + ex.ToString(), "服务商平台查询单笔退款API异常");
  176. }
  177. return return_result;
  178. }
  179. #endregion
  180. #region 服务商平台请求分账API
  181. public string ProfitShare(string SubMchId, string AppId, string TradeNo, string OrderNo, ReceiverList Receivers)
  182. {
  183. Dictionary<string, object> result = new Dictionary<string, object>();
  184. result.Add("sub_mchid", SubMchId); //子商户号
  185. result.Add("appid", AppId); //应用ID
  186. result.Add("transaction_id", TradeNo); //微信订单号
  187. result.Add("out_order_no", OrderNo); //商户分账单号
  188. result.Add("receivers", Receivers); //分账接收方列表
  189. result.Add("unfreeze_unsplit", true); //是否解冻剩余未分资金
  190. string req = Newtonsoft.Json.JsonConvert.SerializeObject(result);
  191. string resp = function.PostWebRequest("https://api.mch.weixin.qq.com/v3/profitsharing/orders", req, "application/json");
  192. return resp;
  193. }
  194. #endregion
  195. #region 服务商平台查询分账结果API
  196. public string QueryProfitShare(string SubMchId, string TradeNo, string OrderNo)
  197. {
  198. string resp = function.GetWebRequest("https://api.mch.weixin.qq.com/v3/profitsharing/orders/" + OrderNo + "?sub_mchid=" + SubMchId + "&transaction_id=" + TradeNo);
  199. return resp;
  200. }
  201. #endregion
  202. #region 服务商平台解冻剩余资金API
  203. public string Unfreeze(string SubMchId, string TradeNo, string OrderNo, string Description)
  204. {
  205. Dictionary<string, object> result = new Dictionary<string, object>();
  206. result.Add("sub_mchid", SubMchId); //子商户号
  207. result.Add("transaction_id", TradeNo); //微信订单号
  208. result.Add("out_order_no", OrderNo); //商户分账单号
  209. result.Add("description", Description); //分账描述
  210. string req = Newtonsoft.Json.JsonConvert.SerializeObject(result);
  211. string resp = function.PostWebRequest("https://api.mch.weixin.qq.com/v3/profitsharing/orders/unfreeze", req, "application/json");
  212. return resp;
  213. }
  214. #endregion
  215. #region 微信客服
  216. public string CustomerServiceChat()
  217. {
  218. return "需要对接";
  219. }
  220. #endregion
  221. #region 获取平台证书
  222. public string GetPlatCert()
  223. {
  224. string merchantId = "1611167423"; //商户号
  225. string serialNo = "62B64854B768D344249FDB9E6EF4A1232C000E84"; //证书编号
  226. string result = postJson("https://api.mch.weixin.qq.com/v3/certificates", "", prikey, merchantId, serialNo, "GET");
  227. return result;
  228. //{"data":[{"effective_time":"2022-01-23T14:02:08+08:00","encrypt_certificate":{"algorithm":"AEAD_AES_256_GCM","associated_data":"certificate","ciphertext":"R+Z85w96Lv7GjtL2zGcwTugGAQkmRUnbKqpQ3VYU8cNcdamTTcJIOgFSXLdHykB1OC70onaRcTxX2Tp1RxlSVm8fbiJBtWpHw28qBIvziJDT9n9R8kF3ayofYulh0mE+46a2jnwO3ioccTaqaDM1qVChElmdksZ3ir79JZn+QfyMcn+O7Pw0x4raT9MROoKFNThX4INzMsyUW7x28dC7v6XKiFxw41bbxIF4qPtUqkKZCAOBcoA8zlyfo3uoLmTAkBoT+V/S8GUhSqXVP9hKotWjDhAzgy8js+R8I3aU6FY2hBK/wOvSSEyleD2YANZNe9Mh8mNoqjuJu8XRNE3n7iJKFcsaFjWHYGABU375xmJngVrqd70fL0TLuMwM+zXOgq3H8HP8TpAhrnQ1yLHd8LJR+KGhlU0Ef89AdLA0Uo/eyaf7EXozWSEqbdmS8EdOse9n4XAEVcx4jNa9rSgg5MggdCwjCye/CbzeucevpEo0Qyl+kGiu1kDsRyaLH8XmgqXXxxiH9WkjrQSDKTwzYudfqrRNdwG6q0MO4krCk4tRYYleLb3Tvvbyr2ffmly42VirXcp+H/f2B/qeD8iGa2PPxinrb3YZCi+E1g+bevRpz+HhXVNBmbkNceOc0hAmA5ul++t0hEJ5YaI7562CGKY6/bctSHIH+zQk0oAi9Wb5TebagGbNcdUOwuE8nZM1HA1hkN57h8ITA7yrGw/YVCYSsLdDHJS/Mo8Bcus/yCWqfo7/aeAkua29ipsrRCXTGc220nS+PsnS2tYXXpFBh13EW9J1cyPbNaT+i1GOe/LSX1zLYIALuIw1wt6adNJ4CtFWyEUYb/cLxveVlUtP1iUEFM7BMNil69/2SSFz4TTIoEL1ceuPMFvT4R8gL33r9EFdwrc9vo2bmyruyD+n7dLtLNcAh9KoC1rCOoEZHcYCpdQNR3NUb0qRDwb0I19CFZWEgNq4eJqepxkRtMXcF84wpvlhOtLtmbQbjO64JPIUsiQbvfadOLlB+RSYVtaEw/ZGUPyimCakTYffNyUz+aq7emM81Tc1EGT9OOQkY6JYDmIRjK8Q4NTgHmyniovaqD6dp6kW69lL3RfrcN4dOEHqzBcvgcrSkkSKB49sqJckQgmsGHCcm8w/gFxMe6tJY6ol1CYeliYWDl9zl6vPUIeWqUQVADifUk7vrBLcchTqP39+OMJat1KkDE3p1rgwqk/c1DCaFGhtOevnma6E3DMRTPuI7AvUEk+pUKkNUyOEfXJeXA6yr2tHJN1u3Qg5mS/n5maGkhBW0M9fkkNkoC4KGXmGuh5pnl3bPCeugAg7ggtkLD7SqwotdgVbx33Lng2NlsOozJSFGhIZCCicCKwY5BFec73KrQJgo3VtrKppujssB4ag3nA3VcPunPg/ezMTdYbX6sl9/fRxgMafrQzOcKq0JdujwAz4Ecw6HCUyY420+P7qpUijnOhvTNX2ug37OwxhOcqGMzd8d4C4j7246CRgS7dahYOShtV8iBYbiy+F+kzudQgzKY9aD93IMjpNeuUpujzv9KRgqJRwxD9OxwnjMiLz+Mo4psNvl0GTSF3J+AdS6oeF5l4BmhGrXEEMe/KUook3m7s86MkoIKDM4nszNY8HdzzXdjfw+6Qh0oQd7eW0nwFPPtac0yVSjqrLQzKQsqYs4F7zF0eKwWyhRuR5N23Rk4MX49YIYMjXbWB6iiricIRiO1f6HJ8Xf6F66RFJy4dYR1uwWdKGk6kc5ZMSn0HE6zqGBdZQV3BsEkz6wJZ1ZOpFThr0vA9poN0F32c2mJyXDtB1qMytUiEKWyPy2sJ6BIXSB6DsDXQ9U9QGBnKjQ8+yvCglocPjs6JA84cjhXFeR8ElWNmZJ/njUlmlHQ==","nonce":"92306d7e8732"},"expire_time":"2027-01-22T14:02:08+08:00","serial_no":"62B64854B768D344249FDB9E6EF4A1232C000E84"}]}
  229. }
  230. public string AesGcmDecrypt(string associatedData, string nonce, string ciphertext)
  231. {
  232. GcmBlockCipher gcmBlockCipher = new GcmBlockCipher(new AesEngine());
  233. AeadParameters aeadParameters = new AeadParameters(
  234. new KeyParameter(Encoding.UTF8.GetBytes(AppConfig.WeChatParam.AesGemKey)),
  235. 128,
  236. Encoding.UTF8.GetBytes(nonce),
  237. Encoding.UTF8.GetBytes(associatedData));
  238. gcmBlockCipher.Init(false, aeadParameters);
  239. byte[] data = Convert.FromBase64String(ciphertext);
  240. byte[] plaintext = new byte[gcmBlockCipher.GetOutputSize(data.Length)];
  241. int length = gcmBlockCipher.ProcessBytes(data, 0, data.Length, plaintext, 0);
  242. gcmBlockCipher.DoFinal(plaintext, length);
  243. return Encoding.UTF8.GetString(plaintext);
  244. }
  245. public string GetPublicKey()
  246. {
  247. var result = Newtonsoft.Json.JsonConvert.DeserializeObject<certModel>(GetPlatCert());
  248. var cmodel = result.data.OrderByDescending(t => t.expire_time).FirstOrDefault();
  249. string pubkey = AesGcmDecrypt(cmodel.encrypt_certificate.associated_data, cmodel.encrypt_certificate.nonce, cmodel.encrypt_certificate.ciphertext);
  250. pubkey = pubkey.Replace("-----BEGIN CERTIFICATE-----", "").Replace("-----END CERTIFICATE-----", "").Replace("\n", "");
  251. return pubkey;
  252. }
  253. #endregion
  254. #region 敏感信息加密
  255. // string pubkey = "MIIBCgKCAQEAxK9K2ElQ0rUMwNFW4xMx7kmkpDlp7WGQ8VffXLpudJBIrRVFWJN7dlinCGu67ZATf+/GZvLSSzQPWejHEsI9vUp9ej0x5iZDHGc9/shNUjd03ORkKo/Ohj3Ju19RzX4mh+GoinKGiuKX8CdGPXPe7UObKWyETrDcxrit6VCJQjE604aNtVeAUE+41mOpCLGzTgAKt4psfHxsBRtqlveH4cH/51ip+cGkC/u36gfDMKaRluVfFO3ETxDkI94BwNtnthcA4WDKha+wjtB6HIJ5xxHV550+cfdkl4j8UKU6pB+C5JRNgvjAf6ljg/TF+cGF1d8C6IbYYodYKloqN2DzrwIDAQAB"; //公钥
  256. string pubkey = "MIID3DCCAsSgAwIBAgIUU0FlQhvigU3sCPjQC9q5lEsTZGwwDQYJKoZIhvcNAQELBQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsTFFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3QgQ0EwHhcNMjEwNjMwMDMwOTA5WhcNMjYwNjI5MDMwOTA5WjBuMRgwFgYDVQQDDA9UZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRlbnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGDAJDTjERMA8GA1UEBwwIU2hlblpoZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC64SIwN1afgge2pjFeNZAlKz5ZdJw8W/hisaIJnkzbE/1oG5n+SgtbMLfBLBFp0zMyT5SP5ve5aJAvUjwnRwQoDG+4z3jE8vLyjFLxoy5sWGex8+FBC5hs81oAUHuazigi5NcSH9Ji/8Lq3zFh8Az4+ZchQ14SFhSGTifSZfdTX5wYDEv3DKDYgQvvAgDgjBF1Uj91NpVD7ruQjAJ7MwZvUX7rnYFnQggFQwIBWazNXaGa7OpO6Xbf+uNtbl436My7WQX+ffjmtYmcgND60mgn/rFQMg5r+Q+J8mDgIaAzCmr3xW31OIvAD1iYV0ksTyQntD5pOzCYdHZPDOZCqYlHAgMBAAGjgYEwfzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIE8DBlBgNVHR8EXjBcMFqgWKBWhlRodHRwOi8vZXZjYS5pdHJ1cy5jb20uY24vcHVibGljL2l0cnVzY3JsP0NBPTFCRDQyMjBFNTBEQkMwNEIwNkFEMzk3NTQ5ODQ2QzAxQzNFOEVCRDIwDQYJKoZIhvcNAQELBQADggEBAEgXlFe4MpFUUnj6gJt5KoPpzLTNOXDHsglUrAobq/HlmDBOF8yCUFvtbRaJxUSQVFfo/2zag8J57YNMo2If1HkD1LMEGAcPGNS+aho9SgCFbLG+c82nNICl8g8oe1HNS7IpRjacSfrKIYt5VL5lHHC5ZJaKq0Ez9c7bfPGC6CaA8WDnApFZut5qhYNMBUYZZjAMVIZ2G/kIsxbo1oUpVEnQq5YQxPUDWdYKxdTvo7uXXpWv6qo761Hid24R7mdrGEuHZNBfxYCt1wJQNlcGVgCjk8PPo73mO0zYRwV0x7pNkFFbiP7aetf6RB82YUbuNkvql83Ox+e22ByMi8lOUZo=";
  257. string prikey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQD7f7VmtjtLJaY+oJkMgDN9dDE082ZOgquHorPrtJNEdf7VjRFLMoKOoiQsT4OgVq3lNN2KKndd5ahsegSq7Ng7aYJq7IDH584RWEGbekEn0M10aXThdk9dPSCMXBPFR6y4gMvV4R6pVbPBxoSFMI6ty+EqfZLP9Cxvxx7msIKEB46r2R6gYL7j061ytoURavUxGAZxMXnCAEckbrssiFwhLTmX6TtC8MVPyUfLPUh07ArRZxK2F0hpX35Te0Jda7xkulbWtz4EB8KPXr0bJGO/oUo+Prqpdjy0+zKMfMvBP6NG1Hnh3z7yBhlYIe4vymFQU1Wy0OtrEbrU1OdJiq5XAgMBAAECggEAJ7biAWczc8ltOCSKJpQ0DVKE1rS86hbuWUvTF5x7SOtNI5HUMki2nylxhuHDilVFvpUbis7r7JLwhri59ffSqYcexh20tFyhiNGkApZKpavuVby1bUkOfU3CzwdXQ+bumnAUQCD9g4X6DdZ4ZMPnNACm/Nu5jEcloT0TXyBua8SpmlFMYgo/x8XOTT4dEeubwNsfEpmSeWcQRJLJI5ujGgmmZLiAs7F3VlCJFNtQa1KT3a1EDhD5jajeQAzsPpQ48i/joOqE71RlVr77z4Ethr8o1Cc16K9Md2AtVesMZ6eZNqKkQ/qC3vnxk5Sy25tuVmOCXa81ErIf9Tf/JwhymQKBgQD/TXnYxEzYJCqa7/Ck6QqBHQf4ak1OVz7/NY7bmxYT5ez4eJKzrh+xQYWBq/UmKeEiH5QI6T3MVo7L20tbeuYLQwYpgb+BpOKHFne2ODOgDYreNREB06Ww2qAQYCqwyBnTqt7UthDmcXhcPojwxNLSJAOCQhld9TOOmK1db33PIwKBgQD8L5KiN9XRFCvUH6rhUcs/8lmGR2N8zSTts+BNCwIPGQWE0UvbjroyNxVbq6cXXlZZ6H07vEAgaIrLIkwLgen2IwsuOiyaEMvRP9oGwC+LnpP+9sxbW5w5do1hfyeGiSPPgSYIWZMOOwX+qfqXDMM3whJP1hk4El87kC+kl2URPQKBgQC4kTc8ebWgMI1Ik5wibIN2khlYAum+cB6P/BU6OCU+32NwwiI0mfY5fEfbVgiVvYMP20p3Ir/VgOIdCH2zNecnTx4eVbmwLRbDWH/VEU5pMEEroauY6XyInZVIIW3bfd4GAyqzFqijIHdGIMN5ZKGQ4A5VVhnmrkTGmyQCP37xhwKBgQCaLW+Fc4NqTt240x+Cn6IWV1E6UfzV+QmBtb4E/BznJBIGsHqjIbBeMOUC5X/DPq6mSwf9dEr0RVXNeQtq4aMrEyOrwG8yReCF7naaN/cZcfrjHvmzRN/PFda766Q7kS5ul3OsGS9ZvOYeWsdUf73+Ic1WN/u1Fy5X2P/3rYNhtQKBgAIioAq8psFdy/itpJryaWdmDM6fM6ctp5P6VBWOVp2JGkOzHboiXFToJJBtmi7Rdp8AN1aYBbtVX1o0+RmfEiHqXn84GpSNT6tGirHvARi5ab3jvn+bkUWjZYOGd96hus8GirA+wQb/V92Ms3jS5VUS1HBfHaTGT5G2Slrr8YZu"; //私钥
  258. public string RSAEncrypt(string text)
  259. {
  260. byte[] publicKey = Convert.FromBase64String(pubkey);
  261. // var rsa = RSA.Create();
  262. // rsa.ImportRSAPublicKey(publicKey, out _);
  263. // var buff = rsa.Encrypt(Encoding.UTF8.GetBytes(text), RSAEncryptionPadding.OaepSHA1);
  264. // return Convert.ToBase64String(buff);
  265. using (var x509 = new X509Certificate2(publicKey))
  266. {
  267. using (var rsa = x509.GetRSAPublicKey())
  268. {
  269. var buff = rsa.Encrypt(Encoding.UTF8.GetBytes(text), RSAEncryptionPadding.OaepSHA1);
  270. return Convert.ToBase64String(buff);
  271. }
  272. }
  273. }
  274. public string postJson(string url, string postData, string privateKey, string merchantId, string serialNo, string method = "POST")
  275. {
  276. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
  277. request.Method = method;
  278. request.ContentType = "application/json;charset=UTF-8";
  279. 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";
  280. request.Accept = "application/json";
  281. string Authorization = GetAuthorization(url, method, postData, privateKey, merchantId, "62B64854B768D344249FDB9E6EF4A1232C000E84");
  282. request.Headers.Add("Authorization", Authorization);
  283. request.Headers.Add("Wechatpay-Serial", serialNo);
  284. if (!string.IsNullOrEmpty(postData))
  285. {
  286. byte[] paramJsonBytes;
  287. paramJsonBytes = System.Text.Encoding.UTF8.GetBytes(postData);
  288. request.ContentLength = paramJsonBytes.Length;
  289. Stream writer;
  290. try
  291. {
  292. writer = request.GetRequestStream();
  293. }
  294. catch (Exception)
  295. {
  296. writer = null;
  297. Console.Write("连接服务器失败!");
  298. }
  299. writer.Write(paramJsonBytes, 0, paramJsonBytes.Length);
  300. writer.Close();
  301. }
  302. HttpWebResponse response;
  303. try
  304. {
  305. response = (HttpWebResponse)request.GetResponse();
  306. }
  307. catch (WebException ex)
  308. {
  309. response = ex.Response as HttpWebResponse;
  310. }
  311. Stream resStream = response.GetResponseStream();
  312. StreamReader reader = new StreamReader(resStream);
  313. string text = reader.ReadToEnd();
  314. return text;
  315. //{\"code\":\"PARAM_ERROR\",\"message\":\"请确认待处理的消息是否为加密后的密文\"}
  316. //{\"applyment_id\":2000002247709762}
  317. }
  318. #endregion
  319. #region 图片上传
  320. public string GetMediaId(string imgPath)
  321. {
  322. if (string.IsNullOrEmpty(imgPath))
  323. {
  324. return "";
  325. }
  326. string key = "wechatpic:" + function.MD5_16(imgPath);
  327. string media_id = RedisDbconn.Instance.Get<string>(key);
  328. if (!string.IsNullOrEmpty(media_id))
  329. {
  330. return media_id;
  331. }
  332. string filePath = function.getPath(imgPath);
  333. var filename = Path.GetFileName(filePath);
  334. FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
  335. Byte[] imgBytesIn = new Byte[fs.Length];
  336. fs.Read(imgBytesIn, 0, imgBytesIn.Length);
  337. fs.Close();
  338. byte[] hash = SHA256Managed.Create().ComputeHash(imgBytesIn);
  339. StringBuilder builder = new StringBuilder();
  340. for (int i = 0; i < hash.Length; i++)
  341. {
  342. builder.Append(hash[i].ToString("x2"));
  343. }
  344. var sha256 = builder.ToString();
  345. string metaStr = "{\"filename\":\""+ filename + "\",\"sha256\":\"" + sha256 + "\"}";
  346. media_id = UploadImgApi(metaStr, imgBytesIn, filename);
  347. return media_id;
  348. }
  349. public string UploadImgApi(string metaStr, Byte[] imgBytesIn,string filename)
  350. {
  351. string url = "https://api.mch.weixin.qq.com/v3/merchant/media/upload";
  352. string merchantId = "1611167423"; //商户号
  353. string serialNo = "62B64854B768D344249FDB9E6EF4A1232C000E84"; //证书编号
  354. string privateKey = prikey;
  355. #region 定义请求体中的内容 并转成二进制
  356. string boundary = "lc199aecd61b4653ef";
  357. string Enter = "\r\n";
  358. string campaignIDStr1
  359. = "--" + boundary
  360. + Enter
  361. + "Content-Disposition: form-data; name=\"meta\";"
  362. + Enter
  363. + "Content-Type:application/json;"
  364. + Enter
  365. + Enter
  366. + metaStr
  367. + Enter
  368. + "--" + boundary
  369. + Enter
  370. + "Content-Disposition:form-data;name=\"file\";filename=\""+ filename + "\";"
  371. + Enter
  372. + "Content-Type:image/jpeg"
  373. + Enter
  374. + Enter;
  375. byte[] byteData2
  376. = imgBytesIn;
  377. string campaignIDStr3
  378. = Enter
  379. + "--" + boundary
  380. + Enter;
  381. var byteData1 = System.Text.Encoding.UTF8.GetBytes(campaignIDStr1);
  382. var byteData3 = System.Text.Encoding.UTF8.GetBytes(campaignIDStr3);
  383. #endregion
  384. string transactionsResponse = UploadImg_postJson(url, byteData1, byteData2, byteData3, metaStr, privateKey, merchantId, serialNo, boundary, "POST");
  385. var result=JsonMapper.ToObject(transactionsResponse);
  386. return result["media_id"].ToString();
  387. }
  388. public string UploadImg_postJson(string url, byte[] b1, byte[] b2, byte[] b3, string metaStr, string privateKey, string merchantId, string serialNo, string boundary, string method = "POST")
  389. {
  390. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
  391. request.Method = method;
  392. //request.ContentType = "application/json;charset=UTF-8";
  393. request.ContentType = "multipart/form-data;boundary=" + boundary;
  394. 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";
  395. request.Accept = "application/json";
  396. string Authorization = GetAuthorization(url, method, metaStr, privateKey, merchantId, serialNo);
  397. request.Headers.Add("Authorization", Authorization);
  398. Stream writer;
  399. try
  400. {
  401. writer = request.GetRequestStream();
  402. }
  403. catch (Exception)
  404. {
  405. writer = null;
  406. }
  407. writer.Write(b1, 0, b1.Length);
  408. writer.Write(b2, 0, b2.Length);
  409. writer.Write(b3, 0, b3.Length);
  410. writer.Close();
  411. HttpWebResponse response;
  412. try
  413. {
  414. response = (HttpWebResponse)request.GetResponse();
  415. }
  416. catch (WebException ex)
  417. {
  418. response = ex.Response as HttpWebResponse;
  419. }
  420. Stream resStream = response.GetResponseStream();
  421. StreamReader reader = new StreamReader(resStream);
  422. string text = reader.ReadToEnd();
  423. return text;
  424. }
  425. protected string GetAuthorization(string url, string method, string jsonParame, string privateKey, string merchantId, string serialNo)
  426. {
  427. var uri = new Uri(url);
  428. string urlPath = uri.PathAndQuery;
  429. string nonce = Guid.NewGuid().ToString();
  430. var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
  431. //数据签名 HTTP请求方法\n接口地址的url\n请求时间戳\n请求随机串\n请求报文主体\n
  432. method = string.IsNullOrEmpty(method) ? "" : method;
  433. string message = string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n", method, urlPath, timestamp, nonce, jsonParame);
  434. string signTxt = Sign(message, privateKey);
  435. //Authorization和格式
  436. string authorzationTxt = string.Format("WECHATPAY2-SHA256-RSA2048 mchid=\"{0}\",nonce_str=\"{1}\",timestamp=\"{2}\",serial_no=\"{3}\",signature=\"{4}\"",
  437. merchantId,
  438. nonce,
  439. timestamp,
  440. serialNo,
  441. signTxt
  442. );
  443. return authorzationTxt;
  444. }
  445. protected string Sign(string message, string privateKey)
  446. {
  447. byte[] keyData = Convert.FromBase64String(privateKey);
  448. byte[] data = System.Text.Encoding.UTF8.GetBytes(message);
  449. var rsa = RSA.Create();
  450. rsa.ImportPkcs8PrivateKey(keyData, out _);
  451. return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
  452. // using (CngKey cngKey = CngKey.Import(keyData, CngKeyBlobFormat.Pkcs8PrivateBlob))
  453. // using (RSACng rsa = new RSACng(cngKey))
  454. // {
  455. // return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
  456. // }
  457. }
  458. #endregion
  459. #region 获取文件sha256
  460. public string GetSha256(FileStream stream)
  461. {
  462. using (SHA256 mySHA256 = SHA256.Create())
  463. {
  464. byte[] hashValue = mySHA256.ComputeHash(stream);
  465. return Encoding.UTF8.GetString(hashValue);
  466. }
  467. }
  468. #endregion
  469. #region 判断长期
  470. public string CheckForever(DateTime? time)
  471. {
  472. if (time == null)
  473. {
  474. return "";
  475. }
  476. if (time.Value.Year >= 2050)
  477. {
  478. return "长期";
  479. }
  480. return time.Value.ToString("yyyy-MM-dd");
  481. }
  482. #endregion
  483. }
  484. }