WeChatFunction.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. using System;
  2. using System.Collections.Generic;
  3. using Library;
  4. using System.Security.Cryptography.X509Certificates;
  5. using System.Security.Cryptography;
  6. using System.Text;
  7. using System.IO;
  8. using LitJson;
  9. using System.Net;
  10. namespace MySystem
  11. {
  12. public class WeChatFunction
  13. {
  14. public WeChatFunction()
  15. {
  16. }
  17. #region 服务商平台查询申请单状态API
  18. public Dictionary<string, object> QueryMerchant(string BusinessCode)
  19. {
  20. Dictionary<string, object> return_result = new Dictionary<string, object>();
  21. try
  22. {
  23. string merchantId = "1613112281"; //商户号
  24. string serialNo = "61D99F7218B487788E35D6C4E3ED398E0979D3F6"; //证书编号
  25. string result = postJson("https://api.mch.weixin.qq.com/v3/applyment4sub/applyment/business_code/" + BusinessCode, "", prikey, merchantId, serialNo, "GET");
  26. //{\"applyment_id\":2000002247709762,\"applyment_state\":\"APPLYMENT_STATE_FINISHED\",\"applyment_state_msg\":\"商户入驻申请已完成\",\"audit_detail\":[],\"business_code\":\"0123456789\",\"sign_url\":\"https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=gQFv7zwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyUXE1czkzb3JlUjIxZHpXbTF5Y2YAAgRjbe9hAwQAjScA\",\"sub_mchid\":\"1619775262\"}
  27. JsonData jsonObj = JsonMapper.ToObject(result);
  28. return_result.Add("applyment_id", jsonObj["applyment_id"].ToString()); //微信支付申请单号
  29. return_result.Add("applyment_state", jsonObj["applyment_state"].ToString()); //申请单状态
  30. return_result.Add("applyment_state_msg", jsonObj["applyment_state_msg"].ToString()); //申请状态描述
  31. if (jsonObj["applyment_state"].ToString() == "APPLYMENT_STATE_REJECTED")
  32. {
  33. List<Dictionary<string, string>> audit_detail = new List<Dictionary<string, string>>();
  34. JsonData auditObj = jsonObj["audit_detail"]; //驳回原因详情
  35. for (int i = 0; i < auditObj.Count; i++)
  36. {
  37. Dictionary<string, string> row = new Dictionary<string, string>();
  38. row.Add("field", auditObj[i]["field"].ToString()); //字段名
  39. row.Add("field_name", auditObj[i]["field_name"].ToString()); //字段名称
  40. row.Add("reject_reason", auditObj[i]["reject_reason"].ToString()); //驳回原因
  41. audit_detail.Add(row);
  42. }
  43. return_result.Add("audit_detail", audit_detail); //申请状态描述
  44. }
  45. if (result.Contains("\"sign_url\":"))
  46. {
  47. return_result.Add("sign_url", jsonObj["sign_url"].ToString()); //进件通过申请,待商家签约的地址
  48. }
  49. }
  50. catch (Exception ex)
  51. {
  52. function.WriteLog(DateTime.Now.ToString() + "\r\n" + ex.ToString(), "服务商平台查询申请单状态API异常");
  53. }
  54. return return_result;
  55. }
  56. #endregion
  57. #region 敏感信息加密
  58. // string pubkey = "MIIBCgKCAQEAxK9K2ElQ0rUMwNFW4xMx7kmkpDlp7WGQ8VffXLpudJBIrRVFWJN7dlinCGu67ZATf+/GZvLSSzQPWejHEsI9vUp9ej0x5iZDHGc9/shNUjd03ORkKo/Ohj3Ju19RzX4mh+GoinKGiuKX8CdGPXPe7UObKWyETrDcxrit6VCJQjE604aNtVeAUE+41mOpCLGzTgAKt4psfHxsBRtqlveH4cH/51ip+cGkC/u36gfDMKaRluVfFO3ETxDkI94BwNtnthcA4WDKha+wjtB6HIJ5xxHV550+cfdkl4j8UKU6pB+C5JRNgvjAf6ljg/TF+cGF1d8C6IbYYodYKloqN2DzrwIDAQAB"; //公钥
  59. string pubkey = "MIID3DCCAsSgAwIBAgIUYdmfchi0h3iONdbE4+05jgl50/YwDQYJKoZIhvcNAQELBQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsTFFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3QgQ0EwHhcNMjIwMTIzMDYwMjA4WhcNMjcwMTIyMDYwMjA4WjBuMRgwFgYDVQQDDA9UZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRlbnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGDAJDTjERMA8GA1UEBwwIU2hlblpoZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDSFtwof74G5sJuQya6OJKhfjMcVZ3PZk+uG0RWULyDwOZezvYjLp9jkkfTCWuWDkshRmrDhVj89eOPwy60QDYKaKQ1Mq48BqoQrOikSK5bxAMGHg1a/0UcPM3yL3T84nlZkFlySeXN8cqWkZnPIXeO/blYCyBxNizmUwIIJUlI1Fbhy4lQRsoLoRbeh+YUQ2AI9D2plzVDY5jkG9/FQWhyZr5K3rgjblb/pMZngmzSYCNBWfJP9EZfRuQvZokMEddytC3JoSPgvqA25RMAPvj1cnAiOypgm7BHhx+a1mpmz79ifWlDF9rglo6WDGAxQ4JDuPJTVOiQ9EsfS8OHjxmfAgMBAAGjgYEwfzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIE8DBlBgNVHR8EXjBcMFqgWKBWhlRodHRwOi8vZXZjYS5pdHJ1cy5jb20uY24vcHVibGljL2l0cnVzY3JsP0NBPTFCRDQyMjBFNTBEQkMwNEIwNkFEMzk3NTQ5ODQ2QzAxQzNFOEVCRDIwDQYJKoZIhvcNAQELBQADggEBABrLvDmhYbFtIbKZE+up87zfYcx/HvaxIrHNRju7e6Kn62fmxhNRFuOBjMwshBt247lN4w02peBDmAOTRTs8jwamRwqTv6WtO2bbrKT3QkyEDieNnO2kfEIsSAXGp0FUcmkgzZv7tOekGUx8H6yp/3mtpFy1UqE86s5GdQGDVmhOTG2naqidi1X10XnTNWrw3siuc5pSm02lfpwEMl2zyWvQrC/42s/DO8/VfnmIVGy1QIzIpTfUYC6mfTiGuARLIgUwv/wRxrCwSOBKLLbaxXPB2HOaUJ1BpAOyVjxx46Y7yEpfpzkHbm5gNnhICUjQwDT1V2tpslclqjwP0Ju97Mw=";
  60. string prikey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDEr0rYSVDStQzA0VbjEzHuSaSkOWntYZDxV99cum50kEitFUVYk3t2WKcIa7rtkBN/78Zm8tJLNA9Z6McSwj29Sn16PTHmJkMcZz3+yE1SN3Tc5GQqj86GPcm7X1HNfiaH4aiKcoaK4pfwJ0Y9c97tQ5spbIROsNzGuK3pUIlCMTrTho21V4BQT7jWY6kIsbNOAAq3imx8fGwFG2qW94fhwf/nWKn5waQL+7fqB8MwppGW5V8U7cRPEOQj3gHA22e2FwDhYMqFr7CO0HocgnnHEdXnnT5x92SXiPxQpTqkH4LklE2C+MB/qWOD9MX5wYXV3wLohthih1gqWio3YPOvAgMBAAECggEAFSxFo1jpIXWqBMvETbeQRXWaCq+/jnVVVBXAjsvm/hdWK4PBrlJaFRhgCtEGE3LSFpCqTATRzJSzHlunqoZMfScasOELkRoHWXRnwRiw8ivUIb9YZRiMA/l80PXm6XcuEKyjJxxDDYptDsY7knv5wJLpjiEHcS0q5x2UYyxvSjewJMZE8RlGxqvyoSmV2galRssQdpYujG27FAzcK/3SWDY9MjPNnTk9+kMnXXh8VB3fy9Dxpo1plmSwCKf3gnBGuqKcgyzp/5rnjyrGy7Whh5RFcdB7ervFIgCuLVd+Ko2NG3klJx1HUXduQ5laSgSrHwD69LByTEOmkl27l1R5OQKBgQDoj46CbJsnyD7XaTlPaMHIbzkC5QLPBMYqdqk7CvuRVSgbUttDUu4hJGuu+H+8rflg4UE5a++y5ip67XzfGw3KOb98IoHYrRPvZLAfQtiXuedX4I/klBSXMyf6HaI7QPKiH7fW1olpb/NaSMlfKtQR6wgpdZSc2iuiLwvFXuQLQwKBgQDYghN8oRXChpaVsWA8Gg8TkUs2WqcSCI6KWtAWMCTPLWakTQrHdmzsMGu50Q99U4iCCdW7y3+a59scRd+o5HDvD4HAHiSuQxy/F/iWH9y2IymoJyHFAy3iMUIfVhzQpiJCKRxzLkBxRPPE1JDTb6QmPX7t2poFXh9x+wFAMbaxJQKBgG+JqofTHvcNi1Y1GU+EpqxC68z/mUFAwOpMzw2KTu19MicorhC0DZHHrf3VIS6VIi3c2zN3GRdsXKNok6NNjmeXGsempTAOkqkWWYIkxUy/1LzI7zpp6xY5assCu3Q/yh8Hp1xauLzg/I4oqqwCFoQhfWClDAnOeW7nsXWP9T+RAoGANFeeJm87N4AaP65WObGDG5Pwvv9DjNSMwV4bGIIjJAMx4V7O0FINGzzJjm7Ac+gSBH4kMfaMrwKGslsiK06vDtyM3clrzMVk2b4N1x102oO9um1beKnAGgMWnUTQSpEfjycpPZ9c7QVieZ96M+O1p5kOaqqCufF7YK7yKnbaWBECgYEAvTevavXvhR7JTfVbqpPpBK0YUS0c8ys1k699VQeJIbSo2qecCi/xdk9fSHPFd0jjL5+7+g37M8l9KcQex0rnMxYBmIZY9Ce7MfsYt2dOnmLMdpOeiL4REt0Zr9txXrF0jeWlGYUTHl6/vNqKYJug3dpZaak/cj6Pyjyp35v3Ruw="; //私钥
  61. public string RSAEncrypt(string text)
  62. {
  63. byte[] publicKey = Convert.FromBase64String(pubkey);
  64. // var rsa = RSA.Create();
  65. // rsa.ImportRSAPublicKey(publicKey, out _);
  66. // var buff = rsa.Encrypt(Encoding.UTF8.GetBytes(text), RSAEncryptionPadding.OaepSHA1);
  67. // return Convert.ToBase64String(buff);
  68. using (var x509 = new X509Certificate2(publicKey))
  69. {
  70. using (var rsa = x509.GetRSAPublicKey())
  71. {
  72. var buff = rsa.Encrypt(Encoding.UTF8.GetBytes(text), RSAEncryptionPadding.OaepSHA1);
  73. return Convert.ToBase64String(buff);
  74. }
  75. }
  76. }
  77. public string postJson(string url, string postData, string privateKey, string merchantId, string serialNo, string method = "POST")
  78. {
  79. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
  80. request.Method = method;
  81. request.ContentType = "application/json;charset=UTF-8";
  82. 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";
  83. request.Accept = "application/json";
  84. string Authorization = GetAuthorization(url, method, postData, privateKey, merchantId, "4DD075520570E89C215AD816F67083C3DC7053C8");
  85. request.Headers.Add("Authorization", Authorization);
  86. request.Headers.Add("Wechatpay-Serial", serialNo);
  87. if (!string.IsNullOrEmpty(postData))
  88. {
  89. byte[] paramJsonBytes;
  90. paramJsonBytes = System.Text.Encoding.UTF8.GetBytes(postData);
  91. request.ContentLength = paramJsonBytes.Length;
  92. Stream writer;
  93. try
  94. {
  95. writer = request.GetRequestStream();
  96. }
  97. catch (Exception)
  98. {
  99. writer = null;
  100. Console.Write("连接服务器失败!");
  101. }
  102. writer.Write(paramJsonBytes, 0, paramJsonBytes.Length);
  103. writer.Close();
  104. }
  105. HttpWebResponse response;
  106. try
  107. {
  108. response = (HttpWebResponse)request.GetResponse();
  109. }
  110. catch (WebException ex)
  111. {
  112. response = ex.Response as HttpWebResponse;
  113. }
  114. Stream resStream = response.GetResponseStream();
  115. StreamReader reader = new StreamReader(resStream);
  116. string text = reader.ReadToEnd();
  117. return text;
  118. //{\"code\":\"PARAM_ERROR\",\"message\":\"请确认待处理的消息是否为加密后的密文\"}
  119. //{\"applyment_id\":2000002247709762}
  120. }
  121. #endregion
  122. #region 图片上传
  123. public string GetMediaId(string imgPath)
  124. {
  125. if (string.IsNullOrEmpty(imgPath))
  126. {
  127. return "";
  128. }
  129. string key = "wechatpic:" + function.MD5_16(imgPath);
  130. string media_id = BothdisDbconn.Instance.Get<string>(key);
  131. if (!string.IsNullOrEmpty(media_id))
  132. {
  133. return media_id;
  134. }
  135. string filePath = function.getPath(imgPath);
  136. var filename = Path.GetFileName(filePath);
  137. FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
  138. Byte[] imgBytesIn = new Byte[fs.Length];
  139. fs.Read(imgBytesIn, 0, imgBytesIn.Length);
  140. fs.Close();
  141. byte[] hash = SHA256Managed.Create().ComputeHash(imgBytesIn);
  142. StringBuilder builder = new StringBuilder();
  143. for (int i = 0; i < hash.Length; i++)
  144. {
  145. builder.Append(hash[i].ToString("x2"));
  146. }
  147. var sha256 = builder.ToString();
  148. string metaStr = "{\"filename\":\""+ filename + "\",\"sha256\":\"" + sha256 + "\"}";
  149. media_id = UploadImgApi(metaStr, imgBytesIn, filename);
  150. BothdisDbconn.Instance.Set(key, media_id);
  151. return media_id;
  152. }
  153. public string UploadImgApi(string metaStr, Byte[] imgBytesIn,string filename)
  154. {
  155. string url = "https://api.mch.weixin.qq.com/v3/merchant/media/upload";
  156. string merchantId = "1613112281"; //商户号
  157. string serialNo = "4DD075520570E89C215AD816F67083C3DC7053C8"; //证书编号
  158. string privateKey = prikey;
  159. #region 定义请求体中的内容 并转成二进制
  160. string boundary = "lc199aecd61b4653ef";
  161. string Enter = "\r\n";
  162. string campaignIDStr1
  163. = "--" + boundary
  164. + Enter
  165. + "Content-Disposition: form-data; name=\"meta\";"
  166. + Enter
  167. + "Content-Type:application/json;"
  168. + Enter
  169. + Enter
  170. + metaStr
  171. + Enter
  172. + "--" + boundary
  173. + Enter
  174. + "Content-Disposition:form-data;name=\"file\";filename=\""+ filename + "\";"
  175. + Enter
  176. + "Content-Type:image/jpeg"
  177. + Enter
  178. + Enter;
  179. byte[] byteData2
  180. = imgBytesIn;
  181. string campaignIDStr3
  182. = Enter
  183. + "--" + boundary
  184. + Enter;
  185. var byteData1 = System.Text.Encoding.UTF8.GetBytes(campaignIDStr1);
  186. var byteData3 = System.Text.Encoding.UTF8.GetBytes(campaignIDStr3);
  187. #endregion
  188. string transactionsResponse = UploadImg_postJson(url, byteData1, byteData2, byteData3, metaStr, privateKey, merchantId, serialNo, boundary, "POST");
  189. var result=JsonMapper.ToObject(transactionsResponse);
  190. return result["media_id"].ToString();
  191. }
  192. 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")
  193. {
  194. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
  195. request.Method = method;
  196. //request.ContentType = "application/json;charset=UTF-8";
  197. request.ContentType = "multipart/form-data;boundary=" + boundary;
  198. 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";
  199. request.Accept = "application/json";
  200. string Authorization = GetAuthorization(url, method, metaStr, privateKey, merchantId, serialNo);
  201. request.Headers.Add("Authorization", Authorization);
  202. Stream writer;
  203. try
  204. {
  205. writer = request.GetRequestStream();
  206. }
  207. catch (Exception)
  208. {
  209. writer = null;
  210. }
  211. writer.Write(b1, 0, b1.Length);
  212. writer.Write(b2, 0, b2.Length);
  213. writer.Write(b3, 0, b3.Length);
  214. writer.Close();
  215. HttpWebResponse response;
  216. try
  217. {
  218. response = (HttpWebResponse)request.GetResponse();
  219. }
  220. catch (WebException ex)
  221. {
  222. response = ex.Response as HttpWebResponse;
  223. }
  224. Stream resStream = response.GetResponseStream();
  225. StreamReader reader = new StreamReader(resStream);
  226. string text = reader.ReadToEnd();
  227. return text;
  228. }
  229. protected string GetAuthorization(string url, string method, string jsonParame, string privateKey, string merchantId, string serialNo)
  230. {
  231. var uri = new Uri(url);
  232. string urlPath = uri.PathAndQuery;
  233. string nonce = Guid.NewGuid().ToString();
  234. var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
  235. //数据签名 HTTP请求方法\n接口地址的url\n请求时间戳\n请求随机串\n请求报文主体\n
  236. method = string.IsNullOrEmpty(method) ? "" : method;
  237. string message = string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n", method, urlPath, timestamp, nonce, jsonParame);
  238. string signTxt = Sign(message, privateKey);
  239. //Authorization和格式
  240. string authorzationTxt = string.Format("WECHATPAY2-SHA256-RSA2048 mchid=\"{0}\",nonce_str=\"{1}\",timestamp=\"{2}\",serial_no=\"{3}\",signature=\"{4}\"",
  241. merchantId,
  242. nonce,
  243. timestamp,
  244. serialNo,
  245. signTxt
  246. );
  247. return authorzationTxt;
  248. }
  249. protected string Sign(string message, string privateKey)
  250. {
  251. byte[] keyData = Convert.FromBase64String(privateKey);
  252. byte[] data = System.Text.Encoding.UTF8.GetBytes(message);
  253. var rsa = RSA.Create();
  254. rsa.ImportPkcs8PrivateKey(keyData, out _);
  255. return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
  256. // using (CngKey cngKey = CngKey.Import(keyData, CngKeyBlobFormat.Pkcs8PrivateBlob))
  257. // using (RSACng rsa = new RSACng(cngKey))
  258. // {
  259. // return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
  260. // }
  261. }
  262. #endregion
  263. #region 获取文件sha256
  264. public string GetSha256(FileStream stream)
  265. {
  266. using (SHA256 mySHA256 = SHA256.Create())
  267. {
  268. byte[] hashValue = mySHA256.ComputeHash(stream);
  269. return Encoding.UTF8.GetString(hashValue);
  270. }
  271. }
  272. #endregion
  273. #region 判断长期
  274. public string CheckForever(DateTime? time)
  275. {
  276. if (time == null)
  277. {
  278. return "";
  279. }
  280. if (time.Value.Year >= 2050)
  281. {
  282. return "长期";
  283. }
  284. return time.Value.ToString("yyyy-MM-dd");
  285. }
  286. #endregion
  287. }
  288. }