using System; using System.Collections.Generic; using Library; using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography; using System.Text; using System.IO; using LitJson; using System.Net; namespace MySystem { public class WeChatFunction { public WeChatFunction() { } #region 服务商平台查询申请单状态API public Dictionary QueryMerchant(string BusinessCode) { Dictionary return_result = new Dictionary(); try { string merchantId = "1613112281"; //商户号 string serialNo = "61D99F7218B487788E35D6C4E3ED398E0979D3F6"; //证书编号 string result = postJson("https://api.mch.weixin.qq.com/v3/applyment4sub/applyment/business_code/" + BusinessCode, "", prikey, merchantId, serialNo, "GET"); //{\"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\"} JsonData jsonObj = JsonMapper.ToObject(result); return_result.Add("applyment_id", jsonObj["applyment_id"].ToString()); //微信支付申请单号 return_result.Add("applyment_state", jsonObj["applyment_state"].ToString()); //申请单状态 return_result.Add("applyment_state_msg", jsonObj["applyment_state_msg"].ToString()); //申请状态描述 if (jsonObj["applyment_state"].ToString() == "APPLYMENT_STATE_REJECTED") { List> audit_detail = new List>(); JsonData auditObj = jsonObj["audit_detail"]; //驳回原因详情 for (int i = 0; i < auditObj.Count; i++) { Dictionary row = new Dictionary(); row.Add("field", auditObj[i]["field"].ToString()); //字段名 row.Add("field_name", auditObj[i]["field_name"].ToString()); //字段名称 row.Add("reject_reason", auditObj[i]["reject_reason"].ToString()); //驳回原因 audit_detail.Add(row); } return_result.Add("audit_detail", audit_detail); //申请状态描述 } if (result.Contains("\"sign_url\":")) { return_result.Add("sign_url", jsonObj["sign_url"].ToString()); //进件通过申请,待商家签约的地址 } } catch (Exception ex) { function.WriteLog(DateTime.Now.ToString() + "\r\n" + ex.ToString(), "服务商平台查询申请单状态API异常"); } return return_result; } #endregion #region 敏感信息加密 // string pubkey = "MIIBCgKCAQEAxK9K2ElQ0rUMwNFW4xMx7kmkpDlp7WGQ8VffXLpudJBIrRVFWJN7dlinCGu67ZATf+/GZvLSSzQPWejHEsI9vUp9ej0x5iZDHGc9/shNUjd03ORkKo/Ohj3Ju19RzX4mh+GoinKGiuKX8CdGPXPe7UObKWyETrDcxrit6VCJQjE604aNtVeAUE+41mOpCLGzTgAKt4psfHxsBRtqlveH4cH/51ip+cGkC/u36gfDMKaRluVfFO3ETxDkI94BwNtnthcA4WDKha+wjtB6HIJ5xxHV550+cfdkl4j8UKU6pB+C5JRNgvjAf6ljg/TF+cGF1d8C6IbYYodYKloqN2DzrwIDAQAB"; //公钥 string pubkey = "MIID3DCCAsSgAwIBAgIUYdmfchi0h3iONdbE4+05jgl50/YwDQYJKoZIhvcNAQELBQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsTFFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3QgQ0EwHhcNMjIwMTIzMDYwMjA4WhcNMjcwMTIyMDYwMjA4WjBuMRgwFgYDVQQDDA9UZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRlbnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGDAJDTjERMA8GA1UEBwwIU2hlblpoZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDSFtwof74G5sJuQya6OJKhfjMcVZ3PZk+uG0RWULyDwOZezvYjLp9jkkfTCWuWDkshRmrDhVj89eOPwy60QDYKaKQ1Mq48BqoQrOikSK5bxAMGHg1a/0UcPM3yL3T84nlZkFlySeXN8cqWkZnPIXeO/blYCyBxNizmUwIIJUlI1Fbhy4lQRsoLoRbeh+YUQ2AI9D2plzVDY5jkG9/FQWhyZr5K3rgjblb/pMZngmzSYCNBWfJP9EZfRuQvZokMEddytC3JoSPgvqA25RMAPvj1cnAiOypgm7BHhx+a1mpmz79ifWlDF9rglo6WDGAxQ4JDuPJTVOiQ9EsfS8OHjxmfAgMBAAGjgYEwfzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIE8DBlBgNVHR8EXjBcMFqgWKBWhlRodHRwOi8vZXZjYS5pdHJ1cy5jb20uY24vcHVibGljL2l0cnVzY3JsP0NBPTFCRDQyMjBFNTBEQkMwNEIwNkFEMzk3NTQ5ODQ2QzAxQzNFOEVCRDIwDQYJKoZIhvcNAQELBQADggEBABrLvDmhYbFtIbKZE+up87zfYcx/HvaxIrHNRju7e6Kn62fmxhNRFuOBjMwshBt247lN4w02peBDmAOTRTs8jwamRwqTv6WtO2bbrKT3QkyEDieNnO2kfEIsSAXGp0FUcmkgzZv7tOekGUx8H6yp/3mtpFy1UqE86s5GdQGDVmhOTG2naqidi1X10XnTNWrw3siuc5pSm02lfpwEMl2zyWvQrC/42s/DO8/VfnmIVGy1QIzIpTfUYC6mfTiGuARLIgUwv/wRxrCwSOBKLLbaxXPB2HOaUJ1BpAOyVjxx46Y7yEpfpzkHbm5gNnhICUjQwDT1V2tpslclqjwP0Ju97Mw="; 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="; //私钥 public string RSAEncrypt(string text) { byte[] publicKey = Convert.FromBase64String(pubkey); // var rsa = RSA.Create(); // rsa.ImportRSAPublicKey(publicKey, out _); // var buff = rsa.Encrypt(Encoding.UTF8.GetBytes(text), RSAEncryptionPadding.OaepSHA1); // return Convert.ToBase64String(buff); using (var x509 = new X509Certificate2(publicKey)) { using (var rsa = x509.GetRSAPublicKey()) { var buff = rsa.Encrypt(Encoding.UTF8.GetBytes(text), RSAEncryptionPadding.OaepSHA1); return Convert.ToBase64String(buff); } } } public string postJson(string url, string postData, string privateKey, string merchantId, string serialNo, string method = "POST") { 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, privateKey, merchantId, "4DD075520570E89C215AD816F67083C3DC7053C8"); request.Headers.Add("Authorization", Authorization); request.Headers.Add("Wechatpay-Serial", serialNo); 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) { writer = null; Console.Write("连接服务器失败!"); } 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; //{\"code\":\"PARAM_ERROR\",\"message\":\"请确认待处理的消息是否为加密后的密文\"} //{\"applyment_id\":2000002247709762} } #endregion #region 图片上传 public string GetMediaId(string imgPath) { if (string.IsNullOrEmpty(imgPath)) { return ""; } string key = "wechatpic:" + function.MD5_16(imgPath); string media_id = BothdisDbconn.Instance.Get(key); if (!string.IsNullOrEmpty(media_id)) { return media_id; } string filePath = function.getPath(imgPath); var filename = Path.GetFileName(filePath); FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read); Byte[] imgBytesIn = new Byte[fs.Length]; fs.Read(imgBytesIn, 0, imgBytesIn.Length); fs.Close(); byte[] hash = SHA256Managed.Create().ComputeHash(imgBytesIn); StringBuilder builder = new StringBuilder(); for (int i = 0; i < hash.Length; i++) { builder.Append(hash[i].ToString("x2")); } var sha256 = builder.ToString(); string metaStr = "{\"filename\":\""+ filename + "\",\"sha256\":\"" + sha256 + "\"}"; media_id = UploadImgApi(metaStr, imgBytesIn, filename); BothdisDbconn.Instance.Set(key, media_id); return media_id; } public string UploadImgApi(string metaStr, Byte[] imgBytesIn,string filename) { string url = "https://api.mch.weixin.qq.com/v3/merchant/media/upload"; string merchantId = "1613112281"; //商户号 string serialNo = "4DD075520570E89C215AD816F67083C3DC7053C8"; //证书编号 string privateKey = prikey; #region 定义请求体中的内容 并转成二进制 string boundary = "lc199aecd61b4653ef"; string Enter = "\r\n"; string campaignIDStr1 = "--" + boundary + Enter + "Content-Disposition: form-data; name=\"meta\";" + Enter + "Content-Type:application/json;" + Enter + Enter + metaStr + Enter + "--" + boundary + Enter + "Content-Disposition:form-data;name=\"file\";filename=\""+ filename + "\";" + Enter + "Content-Type:image/jpeg" + Enter + Enter; byte[] byteData2 = imgBytesIn; string campaignIDStr3 = Enter + "--" + boundary + Enter; var byteData1 = System.Text.Encoding.UTF8.GetBytes(campaignIDStr1); var byteData3 = System.Text.Encoding.UTF8.GetBytes(campaignIDStr3); #endregion string transactionsResponse = UploadImg_postJson(url, byteData1, byteData2, byteData3, metaStr, privateKey, merchantId, serialNo, boundary, "POST"); var result=JsonMapper.ToObject(transactionsResponse); return result["media_id"].ToString(); } 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") { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Method = method; //request.ContentType = "application/json;charset=UTF-8"; request.ContentType = "multipart/form-data;boundary=" + boundary; 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, metaStr, privateKey, merchantId, serialNo); request.Headers.Add("Authorization", Authorization); Stream writer; try { writer = request.GetRequestStream(); } catch (Exception) { writer = null; } writer.Write(b1, 0, b1.Length); writer.Write(b2, 0, b2.Length); writer.Write(b3, 0, b3.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; } protected string GetAuthorization(string url, string method, string jsonParame, string privateKey, 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接口地址的url\n请求时间戳\n请求随机串\n请求报文主体\n method = string.IsNullOrEmpty(method) ? "" : method; string message = string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n", method, urlPath, timestamp, nonce, jsonParame); string signTxt = Sign(message, privateKey); //Authorization和格式 string authorzationTxt = string.Format("WECHATPAY2-SHA256-RSA2048 mchid=\"{0}\",nonce_str=\"{1}\",timestamp=\"{2}\",serial_no=\"{3}\",signature=\"{4}\"", merchantId, nonce, timestamp, serialNo, signTxt ); return authorzationTxt; } protected string Sign(string message, string privateKey) { byte[] keyData = Convert.FromBase64String(privateKey); byte[] data = System.Text.Encoding.UTF8.GetBytes(message); var rsa = RSA.Create(); rsa.ImportPkcs8PrivateKey(keyData, out _); return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)); // using (CngKey cngKey = CngKey.Import(keyData, CngKeyBlobFormat.Pkcs8PrivateBlob)) // using (RSACng rsa = new RSACng(cngKey)) // { // return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)); // } } #endregion #region 获取文件sha256 public string GetSha256(FileStream stream) { using (SHA256 mySHA256 = SHA256.Create()) { byte[] hashValue = mySHA256.ComputeHash(stream); return Encoding.UTF8.GetString(hashValue); } } #endregion #region 判断长期 public string CheckForever(DateTime? time) { if (time == null) { return ""; } if (time.Value.Year >= 2050) { return "长期"; } return time.Value.ToString("yyyy-MM-dd"); } #endregion } }