WeChatFunction.cs 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  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 string AppId = "wx6e074b8e07b6577e";
  22. public string AppSecret = "883f9ef7831d8ca82168c3fd6dcfb750";
  23. string MchId = "1613112281";
  24. string serialNo = "14E9FD7F0981BEA23F94137607521CB51C4F76EF";
  25. public WeChatFunction(HttpContext context)
  26. {
  27. _context = context;
  28. }
  29. public WeChatFunction()
  30. {
  31. }
  32. #region 领取会员卡
  33. public Dictionary<string, object> GetUserCard(int MerchantId)
  34. {
  35. string token = new WeChat.WeChatPublicClass(_context).getWXToken(AppId, AppSecret);
  36. string resp = function.GetWebRequest("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + token + "&type=wx_card");
  37. JsonData jsonObj = JsonMapper.ToObject(resp);
  38. string ticket = jsonObj["ticket"].ToString();
  39. string timeStamp = function.ConvertDateTimeInt(DateTime.Now).ToString();
  40. string nonce_str = function.get_Random(12);
  41. var pay_param = new SortedList<string, string>
  42. {
  43. {"timeStamp", timeStamp},
  44. {"nonceStr", nonce_str},
  45. {"ticket", ticket}
  46. };
  47. var pay_param_str = String.Join("&", pay_param.Select(item => String.Format("{0}={1}", item.Key.Trim(), item.Value)).ToArray());
  48. string signature = new WeChat.WeChatPublicClass(_context).SHA1(pay_param_str);
  49. Dictionary<string, object> cardExt = new Dictionary<string, object>();
  50. cardExt.Add("timestamp", timeStamp);
  51. cardExt.Add("nonce_str", nonce_str);
  52. cardExt.Add("signature", signature);
  53. return cardExt;
  54. }
  55. #endregion
  56. #region 服务商平台JSAPI下单
  57. public Dictionary<string, string> Pay(string SubMchId, decimal PayMoney, string OrderNo, string Description, string OpenId, string Key, string NotifyUrl, bool IsAct = false)
  58. {
  59. Dictionary<string, string> return_result = new Dictionary<string, string>();
  60. int amount = (int)(PayMoney * 100);
  61. //具体请求参数
  62. SortedList<string, object> par = new SortedList<string, object>();
  63. par.Add("sp_appid", AppId); //服务商应用ID
  64. par.Add("sp_mchid", MchId); //服务商户号
  65. par.Add("sub_mchid", SubMchId); //子商户号
  66. par.Add("description", Description); //商品描述
  67. par.Add("out_trade_no", OrderNo); //商户订单号
  68. par.Add("notify_url", NotifyUrl); //服务商应用ID
  69. Dictionary<string, object> settle_info = new Dictionary<string, object>();
  70. settle_info.Add("profit_sharing", IsAct); //是否指定分账
  71. par.Add("settle_info", settle_info); //结算信息
  72. Dictionary<string, object> amountDic = new Dictionary<string, object>();
  73. amountDic.Add("total", amount); //总金额
  74. par.Add("amount", amountDic); //订单金额
  75. Dictionary<string, object> payer = new Dictionary<string, object>();
  76. payer.Add("sp_openid", OpenId); //用户在服务商appid下的唯一标识
  77. par.Add("payer", payer); //支付者
  78. string req = Newtonsoft.Json.JsonConvert.SerializeObject(par);
  79. function.WriteLog(req, "服务商平台JSAPI下单请求参数");
  80. try
  81. {
  82. function.WriteLog(serialNo, "服务商平台JSAPI下单请求参数");
  83. function.WriteLog(Newtonsoft.Json.JsonConvert.SerializeObject(par), "服务商平台JSAPI下单请求参数");
  84. string result = postJson("https://api.mch.weixin.qq.com/v3/pay/partner/transactions/jsapi", req, prikey, MchId, serialNo);
  85. function.WriteLog(result, "服务商平台JSAPI下单请求参数");
  86. JsonData jsonObj = JsonMapper.ToObject(result);
  87. string timeStamp = function.ConvertDateTimeInt(DateTime.Now).ToString();
  88. string nonce_str = function.get_Random(12);
  89. string package = "prepay_id=" + jsonObj["prepay_id"].ToString();
  90. var pay_param = new SortedList<string, string>
  91. {
  92. {"appId", AppId},
  93. {"timeStamp", timeStamp},
  94. {"nonceStr", nonce_str},
  95. {"package", package},
  96. {"signType", "RSA"}
  97. };
  98. var pay_param_str = "";
  99. pay_param_str += AppId + "\n";
  100. pay_param_str += timeStamp + "\n";
  101. pay_param_str += nonce_str + "\n";
  102. pay_param_str += package + "\n";
  103. string paySign = Sign(pay_param_str, prikey);
  104. return_result.Add("appId", AppId);
  105. return_result.Add("timeStamp", timeStamp);
  106. return_result.Add("nonceStr", nonce_str);
  107. return_result.Add("package", package);
  108. return_result.Add("paySign", paySign);
  109. }
  110. catch (Exception ex)
  111. {
  112. function.WriteLog(DateTime.Now.ToString() + "\r\n" + ex.ToString(), "服务商品台JSAPI下单异常");
  113. }
  114. return return_result;
  115. }
  116. #endregion
  117. #region 服务商平台申请退款API
  118. 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)
  119. {
  120. Dictionary<string, string> return_result = new Dictionary<string, string>();
  121. int refund = (int)(RefundMoney * 100);
  122. int amount = (int)(TotalMoney * 100);
  123. //具体请求参数
  124. SortedList<string, object> par = new SortedList<string, object>();
  125. par.Add("sub_mchid", SubMchId); //子商户号
  126. par.Add("out_trade_no", OrderNo); //商户订单号
  127. par.Add("out_refund_no", RefundNo); //商户退款单号
  128. Dictionary<string, object> amountDic = new Dictionary<string, object>();
  129. amountDic.Add("refund", refund); //退款金额
  130. amountDic.Add("total", amount); //原订单金额
  131. amountDic.Add("currency", "CNY"); //退款币种
  132. par.Add("amount", amountDic); //金额信息
  133. string req = Newtonsoft.Json.JsonConvert.SerializeObject(par);
  134. function.WriteLog(req, "服务商平台申请退款API");
  135. try
  136. {
  137. string merchantId = MchId; //商户号
  138. string serialNo = "62B64854B768D344249FDB9E6EF4A1232C000E84"; //证书编号
  139. string result = postJson("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds", req, prikey, merchantId, serialNo);
  140. function.WriteLog(result, "服务商平台申请退款API");
  141. JsonData jsonObj = JsonMapper.ToObject(result);
  142. return_result.Add("refund_id", jsonObj["refund_id"].ToString()); //微信支付退款单号
  143. return_result.Add("channel", jsonObj["channel"].ToString()); //退款渠道
  144. return_result.Add("user_received_account", jsonObj["user_received_account"].ToString()); //退款入账账户
  145. return_result.Add("status", jsonObj["status"].ToString()); //退款状态
  146. return_result.Add("payer_total", jsonObj["amount"]["payer_total"].ToString()); //用户支付金额
  147. return_result.Add("payer_refund", jsonObj["amount"]["payer_refund"].ToString()); //用户退款金额
  148. return_result.Add("settlement_refund", jsonObj["amount"]["settlement_refund"].ToString()); //应结退款金额
  149. return_result.Add("settlement_total", jsonObj["amount"]["settlement_total"].ToString()); //应结订单金额
  150. return_result.Add("discount_refund", jsonObj["amount"]["discount_refund"].ToString()); //优惠退款金额
  151. }
  152. catch (Exception ex)
  153. {
  154. function.WriteLog(DateTime.Now.ToString() + "\r\n" + ex.ToString(), "服务商平台申请退款API异常");
  155. }
  156. return return_result;
  157. }
  158. #endregion
  159. #region 服务商平台查询单笔退款API
  160. public Dictionary<string, string> QueryRefund(string RefundNo)
  161. {
  162. Dictionary<string, string> return_result = new Dictionary<string, string>();
  163. try
  164. {
  165. string result = function.GetWebRequest("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/" + RefundNo);
  166. JsonData jsonObj = JsonMapper.ToObject(result);
  167. return_result.Add("refund_id", jsonObj["refund_id"].ToString()); //微信支付退款单号
  168. return_result.Add("transaction_id", jsonObj["transaction_id"].ToString()); //微信支付订单号
  169. return_result.Add("out_trade_no", jsonObj["out_trade_no"].ToString()); //商户订单号
  170. return_result.Add("channel", jsonObj["channel"].ToString()); //退款渠道
  171. return_result.Add("user_received_account", jsonObj["user_received_account"].ToString()); //退款入账账户
  172. return_result.Add("status", jsonObj["status"].ToString()); //退款状态
  173. return_result.Add("total", jsonObj["amount"]["total"].ToString()); //订单金额
  174. return_result.Add("refund", jsonObj["amount"]["refund"].ToString()); //退款金额
  175. return_result.Add("payer_total", jsonObj["amount"]["payer_total"].ToString()); //用户支付金额
  176. return_result.Add("payer_refund", jsonObj["amount"]["payer_refund"].ToString()); //用户退款金额
  177. return_result.Add("settlement_refund", jsonObj["amount"]["settlement_refund"].ToString()); //应结退款金额
  178. return_result.Add("settlement_total", jsonObj["amount"]["settlement_total"].ToString()); //应结订单金额
  179. return_result.Add("discount_refund", jsonObj["amount"]["discount_refund"].ToString()); //优惠退款金额
  180. }
  181. catch (Exception ex)
  182. {
  183. function.WriteLog(DateTime.Now.ToString() + "\r\n" + ex.ToString(), "服务商平台查询单笔退款API异常");
  184. }
  185. return return_result;
  186. }
  187. #endregion
  188. #region 服务商平台请求分账API
  189. public string ProfitShare(string SubMchId, string TradeNo, string OrderNo, List<ReceiverList> Receivers) //有活动分0.62%,没活动不分账
  190. {
  191. Dictionary<string, object> result = new Dictionary<string, object>();
  192. result.Add("sub_mchid", SubMchId); //子商户号
  193. result.Add("appid", AppId); //应用ID
  194. result.Add("transaction_id", TradeNo); //微信订单号
  195. result.Add("out_order_no", OrderNo); //商户分账单号
  196. result.Add("receivers", Receivers); //分账接收方列表
  197. result.Add("unfreeze_unsplit", true); //是否解冻剩余未分资金
  198. string req = Newtonsoft.Json.JsonConvert.SerializeObject(result);
  199. string resp = postJson("https://api.mch.weixin.qq.com/v3/profitsharing/orders", req, prikey, MchId, serialNo);
  200. return resp;
  201. //{"order_id":"30000104462023060249559178531","out_order_no":"2023060210583730173782834","receivers":[{"account":"1613112281","amount":3,"create_time":"2023-06-02T11:34:10+08:00","description":"服务费","detail_id":"36000104462023060269999025889","finish_time":"1970-01-01T08:00:00+08:00","result":"PENDING","type":"MERCHANT_ID"},{"account":"1645266943","amount":7,"create_time":"2023-06-02T11:34:10+08:00","description":"解冻给分账方","detail_id":"36000104462023060269999025890","finish_time":"1970-01-01T08:00:00+08:00","result":"PENDING","type":"MERCHANT_ID"}],"state":"PROCESSING","sub_mchid":"1645266943","transaction_id":"4200001833202306025522158377"}
  202. }
  203. #endregion
  204. #region 服务商平台请求分账回退API
  205. public string ProfitShareReturn(string SubMchId, string ReturnMchId, string OrderNo, string ReturnNo, decimal Amount)
  206. {
  207. int ReturnAmount = (int)(Amount * 100);
  208. Dictionary<string, object> result = new Dictionary<string, object>();
  209. result.Add("sub_mchid", SubMchId); //子商户号
  210. result.Add("out_order_no", OrderNo); //商户分账单号
  211. result.Add("out_return_no", ReturnNo); //商户回退单号
  212. result.Add("return_mchid", ReturnMchId); //回退商户号
  213. result.Add("amount", ReturnAmount); //回退金额
  214. result.Add("description", "用户退款"); //回退描述
  215. string req = Newtonsoft.Json.JsonConvert.SerializeObject(result);
  216. string resp = postJson("https://api.mch.weixin.qq.com/v3/profitsharing/return-orders", req, prikey, MchId, serialNo);
  217. return resp;
  218. }
  219. #endregion
  220. #region 服务商平台添加分账接收方API
  221. public string AddReceive(string SubMchId, string TypeName, string Account, string Name, string Relation)
  222. {
  223. Dictionary<string, object> result = new Dictionary<string, object>();
  224. result.Add("sub_mchid", SubMchId); //子商户号
  225. result.Add("appid", AppId); //应用ID
  226. result.Add("type", TypeName); //分账接收方类型 MERCHANT_ID:商户ID PERSONAL_OPENID:个人openid(由父商户APPID转换得到) PERSONAL_SUB_OPENID:个人sub_openid(由子商户APPID转换得到)
  227. result.Add("account", Account); //分账接收方账号
  228. if(!string.IsNullOrEmpty(Name))
  229. {
  230. result.Add("name", RSAEncrypt(Name)); //分账个人接收方姓名
  231. }
  232. result.Add("relation_type", Relation); //与分账方的关系类型 STORE:门店 STAFF:员工 STORE_OWNER:店主 PARTNER:合作伙伴 HEADQUARTER:总部 BRAND:品牌方 DISTRIBUTOR:分销商 USER:用户 SUPPLIER: 供应商 CUSTOM:自定义
  233. string req = Newtonsoft.Json.JsonConvert.SerializeObject(result);
  234. string resp = postJson("https://api.mch.weixin.qq.com/v3/profitsharing/receivers/add", req, prikey, MchId, serialNo);
  235. return resp;
  236. //{"account":"1613112281","name":"x+8m5jM4x2jSZLDOpN46Js9JyeNgUXkFSmGjCBN45QcSYUNPN86TOheRF64WlwDeO45E/walWPeZSksNN/LfJiB2fZRVun1CJuJ7zxePma8L7iDbKS92i+d38rvOmNTjLhKX64O8oJR4HMtFw1HryxJlUFgM5/ickJ79WGrX3GaVArWisgEzwOyxGBfGSL3ofJhi5TdTnrxHMzqYWv43DRvI9Ja5eMgFbgrGcn+JiJVKQcYj1L8tZ6xQeQCXkY6ubyDiV9wQps2nQA1Oh+UdFcS13Ex4FUSYLCczGFAl4EV8TBJQleZeC1p4ZJquJjje0uMjI2xB6S41yUBoN86gkA==","relation_type":"PARTNER","sub_mchid":"1645266943","type":"MERCHANT_ID"}
  237. }
  238. #endregion
  239. #region 服务商平台查询分账结果API
  240. public string QueryProfitShare(string SubMchId, string TradeNo, string OrderNo)
  241. {
  242. string resp = postJson("https://api.mch.weixin.qq.com/v3/profitsharing/orders/" + OrderNo + "?sub_mchid=" + SubMchId + "&transaction_id=" + TradeNo, "", prikey, MchId, serialNo, "GET");
  243. return resp;
  244. //{"order_id":"30000104462023060249559178531","out_order_no":"2023060210583730173782834","receivers":[{"account":"1613112281","amount":3,"create_time":"2023-06-02T11:34:10+08:00","description":"服务费","detail_id":"36000104462023060269999025889","finish_time":"2023-06-02T11:34:41+08:00","result":"SUCCESS","type":"MERCHANT_ID"},{"account":"1645266943","amount":7,"create_time":"2023-06-02T11:34:10+08:00","description":"解冻给分账方","detail_id":"36000104462023060269999025890","finish_time":"2023-06-02T11:34:41+08:00","result":"SUCCESS","type":"MERCHANT_ID"}],"state":"FINISHED","sub_mchid":"1645266943","transaction_id":"4200001833202306025522158377"}
  245. }
  246. #endregion
  247. #region 服务商平台解冻剩余资金API
  248. public string Unfreeze(string SubMchId, string TradeNo, string OrderNo, string Description)
  249. {
  250. Dictionary<string, object> result = new Dictionary<string, object>();
  251. result.Add("sub_mchid", SubMchId); //子商户号
  252. result.Add("transaction_id", TradeNo); //微信订单号
  253. result.Add("out_order_no", OrderNo); //商户分账单号
  254. result.Add("description", Description); //分账描述
  255. string req = Newtonsoft.Json.JsonConvert.SerializeObject(result);
  256. string resp = postJson("https://api.mch.weixin.qq.com/v3/profitsharing/orders/unfreeze", req, prikey, MchId, serialNo);
  257. return resp;
  258. }
  259. #endregion
  260. #region 微信客服
  261. public string CustomerServiceChat()
  262. {
  263. return "需要对接";
  264. }
  265. #endregion
  266. #region 获取平台证书
  267. public string GetPlatCert()
  268. {
  269. string merchantId = MchId; //商户号
  270. string result = postJson("https://api.mch.weixin.qq.com/v3/certificates", "", prikey, merchantId, serialNo, "GET");
  271. return result;
  272. //{"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"}]}
  273. }
  274. public string AesGcmDecrypt(string associatedData, string nonce, string ciphertext)
  275. {
  276. GcmBlockCipher gcmBlockCipher = new GcmBlockCipher(new AesEngine());
  277. AeadParameters aeadParameters = new AeadParameters(
  278. new KeyParameter(Encoding.UTF8.GetBytes("VyULlqfAW2gBfCNfLdupcL7zlha7d93F")),
  279. 128,
  280. Encoding.UTF8.GetBytes(nonce),
  281. Encoding.UTF8.GetBytes(associatedData));
  282. gcmBlockCipher.Init(false, aeadParameters);
  283. byte[] data = Convert.FromBase64String(ciphertext);
  284. byte[] plaintext = new byte[gcmBlockCipher.GetOutputSize(data.Length)];
  285. int length = gcmBlockCipher.ProcessBytes(data, 0, data.Length, plaintext, 0);
  286. gcmBlockCipher.DoFinal(plaintext, length);
  287. return Encoding.UTF8.GetString(plaintext);
  288. }
  289. public string GetPublicKey()
  290. {
  291. var result = Newtonsoft.Json.JsonConvert.DeserializeObject<certModel>(GetPlatCert());
  292. var cmodel = result.data.OrderByDescending(t => t.expire_time).FirstOrDefault();
  293. string pubkey = AesGcmDecrypt(cmodel.encrypt_certificate.associated_data, cmodel.encrypt_certificate.nonce, cmodel.encrypt_certificate.ciphertext);
  294. pubkey = pubkey.Replace("-----BEGIN CERTIFICATE-----", "").Replace("-----END CERTIFICATE-----", "").Replace("\n", "");
  295. return pubkey;
  296. }
  297. #endregion
  298. #region 敏感信息加密
  299. string pubkey = "MIIEKDCCAxCgAwIBAgIUFOn9fwmBvqI/lBN2B1IctRxPdu8wDQYJKoZIhvcNAQELBQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsTFFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3QgQ0EwHhcNMjMwNjI2MDMwNTU2WhcNMjgwNjI0MDMwNTU2WjCBgTETMBEGA1UEAwwKMTYxMzExMjI4MTEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMS0wKwYDVQQLDCTlm5vlt53nnIHmtqbop4LnsbPnp5HmioDmnInpmZDlhazlj7gxCzAJBgNVBAYMAkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMqiiAP4NhHCJYIhZj0uSwEje1GjwwUFEOS1gr/Y0/oLWgFLdYtVw87ZA9q1PNlfWmNzeknMV42kknDoxiJIOlArMfvMt7Gr9QAxWilqU4N7Q3tNFZzbLJpn6GmkgS764BlA64vkaLMka//RDaaWAbIJTaZxsHFAwdfsf7EdvSJRpn09wmyPENDJ2DL59sQ8g4jZxyhXCtZVHwLOBvuwcjTyhpboCZfnOs+j9MTbKbLcM7WiOynIiN7QCw/nJ0c8ENoDmlS+eu4/y8JWRus9n3Q/FGbFaVaDWlz/5GlrnCHNwdFo/rdqFS/M8oYnyJ5W3kJp3ceaAARPcp9AztEVQGkCAwEAAaOBuTCBtjAJBgNVHRMEAjAAMAsGA1UdDwQEAwID+DCBmwYDVR0fBIGTMIGQMIGNoIGKoIGHhoGEaHR0cDovL2V2Y2EuaXRydXMuY29tLmNuL3B1YmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIwRTUwREJDMDRCMDZBRDM5NzU0OTg0NkMwMUMzRThFQkQyJnNnPUhBQ0M0NzFCNjU0MjJFMTJCMjdBOUQzM0E4N0FEMUNERjU5MjZFMTQwMzcxMA0GCSqGSIb3DQEBCwUAA4IBAQAKd8iaV481kgfT+9V+kQKHFNUzlR+mDbz9aPY8mDTwnHkg3rjtTM05gFFHaUz6RmGxyF9Otb7OWZLORGiIBsb+TcqNco3rwrjihCC5geZnoB48l4+Dk8p8hVczpjKmgGPsGhuDX2nC7BDUj4IKkO5DBHdqWnKReTwzOz3sfhLCnsciOQ+2NFfiXTbgZHBttCNEFLZyyulVZFmH3btb4ZGRHn0URGIMPmEv4JMxoeun/VSzZ17C99oEer3dGOBTOOKlktcSVF7dr2IKg110DIDwAgUg0aq9JsKgXE2sDVzPMwgyYfkgE9aSNAxoxW2MuWopd+7vr/WK2rRtOIwOUYII";
  300. string prikey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDKoogD+DYRwiWCIWY9LksBI3tRo8MFBRDktYK/2NP6C1oBS3WLVcPO2QPatTzZX1pjc3pJzFeNpJJw6MYiSDpQKzH7zLexq/UAMVopalODe0N7TRWc2yyaZ+hppIEu+uAZQOuL5GizJGv/0Q2mlgGyCU2mcbBxQMHX7H+xHb0iUaZ9PcJsjxDQydgy+fbEPIOI2ccoVwrWVR8Czgb7sHI08oaW6AmX5zrPo/TE2ymy3DO1ojspyIje0AsP5ydHPBDaA5pUvnruP8vCVkbrPZ90PxRmxWlWg1pc/+Rpa5whzcHRaP63ahUvzPKGJ8ieVt5Cad3HmgAET3KfQM7RFUBpAgMBAAECggEAKm72xL4JtJZPfHy6CD3VfxuLC4GbqUVyUDKiesJRQZ927aZ7qv3+zyYq5HXnlC2fpAveo+2iuAqqj/Ju62bsrzUcdnpcTVyRJcUv+FRHwNTjQMLXr81F/d+cj+LfGpN2slMiAF2If1s1MpD4ptXq7Pl9xUkxhcXl0e24n8J2hOTs6OT5y+j/bQusptfM0tlWsgGvTlhyTrCLv5gTDmO2Qm7GDKmYGVC2vxtS9oNvfIp2+3VU9LmFZntNcE9fq8m50VJOQ2qkbfI/PT4FPa/+Ot9sNKU4KYGnUw/3uGv9ueUBs8jbroCDlqJDTmF3HjkBVpbA/wqWX9Mp36o0hYhhMQKBgQDpc8dZP3RDgweavrlWWG08KSQBRX0ysNDVzQz1eKES4Azt3CUOB7NraW/k+fzBBNtdEqmYHCBLd3F1MDfB61BAEykGNe1ny05ISAeQHANbpHmLXDRT5gqEpxEjhUkaMNma0Eqyi1v4x+Hu7jLvV1R6m0UUAHi0Lvrv63tO1v5bdwKBgQDeNMcq22zQn41hvnwZnoG56xThkTph5lcZYUHghPLIf0Ib1ibNP5qzklYMBwmSsA5aODFpCkDcLpNDqBUrZldN2Oh26gw/ErPJLTU5drZsf06eOvbqooEG3imlgChcrHtcMHNK6mQtIqRRjZIbUQFaVXCag4mnkDWDnpRmidp7HwKBgQCtAZhik5vdzGT+UQmY679ILlT4fD7kKhUZ3PQVlmgITPJH9DWhyCM3HtRFpN2jTa4js4jrqSxlwQbcCffIRlMaqRhl+eEOYqSI/JheO+RhLerFVHeTFZAF7qnM4SHjvwAEswgoeQ6Xt8m//9bPeLCqjBcNU6wgHBDrbF/ddYba0QKBgH4lLjA5U0P4YBXuQpt0raazOy52+NLdJfMlkHV6ZC3IeOo+n9aDVjq9R5YaZKfexLcZEYvVI08cLcQJ5sK1nbh2/DmN0xf3cRMzU/TkXNmpSCNxy/0V9fPFKZVn9QHvdTS32Kvd9rLc6LXXjetuCDuVJ5DAPeRfbNHks9CmT973AoGBAK400faHTcodLHR/MXEmfI6BZlsTh2Cbm5q+k8Of095xKB/sfTWPprMQW+/U5OEQrKDbt+FI+psJFixmSNFuZdt4JU9P5/bp4SGIQpCfsp1p7GP/irc1yikrHXeGes9HPeUn7yGmvz4QC+sFO32haYr1SaAzZvMhf3RQVuAiFOnw"; //私钥
  301. public string RSAEncrypt(string text)
  302. {
  303. byte[] publicKey = Convert.FromBase64String(pubkey);
  304. // var rsa = RSA.Create();
  305. // rsa.ImportRSAPublicKey(publicKey, out _);
  306. // var buff = rsa.Encrypt(Encoding.UTF8.GetBytes(text), RSAEncryptionPadding.OaepSHA1);
  307. // return Convert.ToBase64String(buff);
  308. using (var x509 = new X509Certificate2(publicKey))
  309. {
  310. using (var rsa = x509.GetRSAPublicKey())
  311. {
  312. var buff = rsa.Encrypt(Encoding.UTF8.GetBytes(text), RSAEncryptionPadding.OaepSHA1);
  313. return Convert.ToBase64String(buff);
  314. }
  315. }
  316. }
  317. public string postJson(string url, string postData, string privateKey, string merchantId, string serialNo, string method = "POST")
  318. {
  319. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
  320. request.Method = method;
  321. request.ContentType = "application/json;charset=UTF-8";
  322. 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";
  323. request.Accept = "application/json";
  324. string Authorization = GetAuthorization(url, method, postData, privateKey, merchantId, serialNo);
  325. request.Headers.Add("Authorization", Authorization);
  326. request.Headers.Add("Wechatpay-Serial", serialNo);
  327. if (!string.IsNullOrEmpty(postData))
  328. {
  329. byte[] paramJsonBytes;
  330. paramJsonBytes = System.Text.Encoding.UTF8.GetBytes(postData);
  331. request.ContentLength = paramJsonBytes.Length;
  332. Stream writer;
  333. try
  334. {
  335. writer = request.GetRequestStream();
  336. }
  337. catch (Exception)
  338. {
  339. writer = null;
  340. Console.Write("连接服务器失败!");
  341. }
  342. writer.Write(paramJsonBytes, 0, paramJsonBytes.Length);
  343. writer.Close();
  344. }
  345. HttpWebResponse response;
  346. try
  347. {
  348. response = (HttpWebResponse)request.GetResponse();
  349. }
  350. catch (WebException ex)
  351. {
  352. response = ex.Response as HttpWebResponse;
  353. }
  354. Stream resStream = response.GetResponseStream();
  355. StreamReader reader = new StreamReader(resStream);
  356. string text = reader.ReadToEnd();
  357. return text;
  358. //{\"code\":\"PARAM_ERROR\",\"message\":\"请确认待处理的消息是否为加密后的密文\"}
  359. //{\"applyment_id\":2000002247709762}
  360. }
  361. #endregion
  362. #region 图片上传
  363. public string GetMediaId(string imgPath)
  364. {
  365. if (string.IsNullOrEmpty(imgPath))
  366. {
  367. return "";
  368. }
  369. string key = "wechatpic:" + function.MD5_16(imgPath);
  370. string media_id = RedisDbconn.Instance.Get<string>(key);
  371. if (!string.IsNullOrEmpty(media_id))
  372. {
  373. return media_id;
  374. }
  375. string filePath = function.getPath(imgPath);
  376. var filename = Path.GetFileName(filePath);
  377. FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
  378. Byte[] imgBytesIn = new Byte[fs.Length];
  379. fs.Read(imgBytesIn, 0, imgBytesIn.Length);
  380. fs.Close();
  381. byte[] hash = SHA256Managed.Create().ComputeHash(imgBytesIn);
  382. StringBuilder builder = new StringBuilder();
  383. for (int i = 0; i < hash.Length; i++)
  384. {
  385. builder.Append(hash[i].ToString("x2"));
  386. }
  387. var sha256 = builder.ToString();
  388. string metaStr = "{\"filename\":\""+ filename + "\",\"sha256\":\"" + sha256 + "\"}";
  389. media_id = UploadImgApi(metaStr, imgBytesIn, filename);
  390. return media_id;
  391. }
  392. public string UploadImgApi(string metaStr, Byte[] imgBytesIn,string filename)
  393. {
  394. string url = "https://api.mch.weixin.qq.com/v3/merchant/media/upload";
  395. string merchantId = MchId; //商户号
  396. string privateKey = prikey;
  397. #region 定义请求体中的内容 并转成二进制
  398. string boundary = "lc199aecd61b4653ef";
  399. string Enter = "\r\n";
  400. string campaignIDStr1
  401. = "--" + boundary
  402. + Enter
  403. + "Content-Disposition: form-data; name=\"meta\";"
  404. + Enter
  405. + "Content-Type:application/json;"
  406. + Enter
  407. + Enter
  408. + metaStr
  409. + Enter
  410. + "--" + boundary
  411. + Enter
  412. + "Content-Disposition:form-data;name=\"file\";filename=\""+ filename + "\";"
  413. + Enter
  414. + "Content-Type:image/jpeg"
  415. + Enter
  416. + Enter;
  417. byte[] byteData2
  418. = imgBytesIn;
  419. string campaignIDStr3
  420. = Enter
  421. + "--" + boundary
  422. + Enter;
  423. var byteData1 = System.Text.Encoding.UTF8.GetBytes(campaignIDStr1);
  424. var byteData3 = System.Text.Encoding.UTF8.GetBytes(campaignIDStr3);
  425. #endregion
  426. string transactionsResponse = UploadImg_postJson(url, byteData1, byteData2, byteData3, metaStr, privateKey, merchantId, serialNo, boundary, "POST");
  427. var result=JsonMapper.ToObject(transactionsResponse);
  428. return result["media_id"].ToString();
  429. }
  430. 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")
  431. {
  432. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
  433. request.Method = method;
  434. //request.ContentType = "application/json;charset=UTF-8";
  435. request.ContentType = "multipart/form-data;boundary=" + boundary;
  436. 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";
  437. request.Accept = "application/json";
  438. string Authorization = GetAuthorization(url, method, metaStr, privateKey, merchantId, serialNo);
  439. request.Headers.Add("Authorization", Authorization);
  440. Stream writer;
  441. try
  442. {
  443. writer = request.GetRequestStream();
  444. }
  445. catch (Exception)
  446. {
  447. writer = null;
  448. }
  449. writer.Write(b1, 0, b1.Length);
  450. writer.Write(b2, 0, b2.Length);
  451. writer.Write(b3, 0, b3.Length);
  452. writer.Close();
  453. HttpWebResponse response;
  454. try
  455. {
  456. response = (HttpWebResponse)request.GetResponse();
  457. }
  458. catch (WebException ex)
  459. {
  460. response = ex.Response as HttpWebResponse;
  461. }
  462. Stream resStream = response.GetResponseStream();
  463. StreamReader reader = new StreamReader(resStream);
  464. string text = reader.ReadToEnd();
  465. return text;
  466. }
  467. protected string GetAuthorization(string url, string method, string jsonParame, string privateKey, string merchantId, string serialNo)
  468. {
  469. var uri = new Uri(url);
  470. string urlPath = uri.PathAndQuery;
  471. string nonce = Guid.NewGuid().ToString();
  472. var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
  473. //数据签名 HTTP请求方法\n接口地址的url\n请求时间戳\n请求随机串\n请求报文主体\n
  474. method = string.IsNullOrEmpty(method) ? "" : method;
  475. string message = string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n", method, urlPath, timestamp, nonce, jsonParame);
  476. string signTxt = Sign(message, privateKey);
  477. //Authorization和格式
  478. string authorzationTxt = string.Format("WECHATPAY2-SHA256-RSA2048 mchid=\"{0}\",nonce_str=\"{1}\",timestamp=\"{2}\",serial_no=\"{3}\",signature=\"{4}\"",
  479. merchantId,
  480. nonce,
  481. timestamp,
  482. serialNo,
  483. signTxt
  484. );
  485. return authorzationTxt;
  486. }
  487. protected string Sign(string message, string privateKey)
  488. {
  489. byte[] keyData = Convert.FromBase64String(privateKey);
  490. byte[] data = System.Text.Encoding.UTF8.GetBytes(message);
  491. var rsa = RSA.Create();
  492. rsa.ImportPkcs8PrivateKey(keyData, out _);
  493. return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
  494. // using (CngKey cngKey = CngKey.Import(keyData, CngKeyBlobFormat.Pkcs8PrivateBlob))
  495. // using (RSACng rsa = new RSACng(cngKey))
  496. // {
  497. // return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
  498. // }
  499. }
  500. #endregion
  501. #region 获取文件sha256
  502. public string GetSha256(FileStream stream)
  503. {
  504. using (SHA256 mySHA256 = SHA256.Create())
  505. {
  506. byte[] hashValue = mySHA256.ComputeHash(stream);
  507. return Encoding.UTF8.GetString(hashValue);
  508. }
  509. }
  510. #endregion
  511. #region 判断长期
  512. public string CheckForever(DateTime? time)
  513. {
  514. if (time == null)
  515. {
  516. return "";
  517. }
  518. if (time.Value.Year >= 2050)
  519. {
  520. return "长期";
  521. }
  522. return time.Value.ToString("yyyy-MM-dd");
  523. }
  524. #endregion
  525. }
  526. }