using Newtonsoft.Json; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Security; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Security; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; using WebService.SDK.PayCommon; namespace WebService.SDK.GZNXPay { public class GZNXPayAPI { /// /// 贵州农信被扫交易接口 /// /// 接口配置 /// 平台商户信息 /// 用户付款授权码 /// 商户交易订单号 /// 交易金额(元) /// public static Model.GZNXPayResultModel ScanPay(GZNXPayConfig payConfig, MobilePayConfig.PayMerchant merchantInfo, string authCode, string merchantOrderCode, string payAmount) { if (payConfig == null) { return default(Model.GZNXPayResultModel); } if (merchantInfo == null || string.IsNullOrWhiteSpace(merchantInfo.MerchantCode)) { return default(Model.GZNXPayResultModel); } if (!decimal.TryParse(payAmount, out decimal _PayAmount) || _PayAmount <= 0) { return default(Model.GZNXPayResultModel); } string _SeqNo = Guid.NewGuid().ToString("N"); //生成交易报文头参数 SortedDictionary _Head = GZNXPayHead(payConfig, merchantInfo, _SeqNo, "siip_order_create_and_pay"); //生成交易报文体参数 SortedDictionary _ApiDictionary = new SortedDictionary { { "ext_order_no", merchantOrderCode },//商户订单号 { "termcode", "0" },//终端号;固定:0 { "term_ip", "" },//终端ip { "operator", "0" },//操作员;固定:0 { "total_amt", (_PayAmount*100).ToString("F0") },//订单金额;单位:分 { "no_discount_amt", "0" }, //不打折金额;单位:分 { "pay_code_type", "AUTO" },//付款码类型;固定:AUTO { "auth_code", authCode },//用户付款码 { "notify_url", "" },//支付成功结果通知地址 { "remark", "" },//备注 { "is_marketing", "N" },//是否可用营销优惠产品 { "goods_sku", "" },//商品SKU编码 { "is_credit_card", "Y" },//是否支持信用卡付款 { "add_data", "" }//自定义附加参数 }; LogHelper.WriteReceiveLog("支付反扫-传第三方参数:【head】" + _Head.Select(pair => pair.Key + "=" + pair.Value). DefaultIfEmpty("").Aggregate((a, b) => a + "&" + b) + "【body】" + _ApiDictionary.Select(pair => pair.Key + "=" + pair.Value). DefaultIfEmpty("").Aggregate((a, b) => a + "&" + b)); //调用银行接口请求交易并返回结果 return JsonConvert.DeserializeObject( HttpUrlPost(ApiParamSign(_Head, _ApiDictionary, payConfig.PlatformKey), payConfig.ScanURL, "application/json", payConfig.PlatformTimeout)); } /// /// 贵州农信交易查询接口 /// /// 接口配置 /// 平台商户信息 /// 商户交易订单号 /// 平台交易订单号 /// 交易金额 /// 累计查询次数 /// public static Model.GZNXPayResultModel QueryPay(GZNXPayConfig payConfig, MobilePayConfig.PayMerchant merchantInfo, string merchantOrderCode, string platformOrderCode, string payType, int queryCount) { if (payConfig == null) { return default(Model.GZNXPayResultModel); } if (merchantInfo == null || string.IsNullOrWhiteSpace(merchantInfo.MerchantCode)) { return default(Model.GZNXPayResultModel); } string _SeqNo = Guid.NewGuid().ToString("N"); //生成交易查询报文头 SortedDictionary _Head = GZNXPayHead(payConfig, merchantInfo, _SeqNo, "siip_order_result_query"); //生成交易查询报文体 SortedDictionary _ApiDictionary = new SortedDictionary { { "query_type", "ext_order_no" },//查询类型 main_order_no:平台订单号 ext_order_no:商户订单号 { "query_no", merchantOrderCode }//查询号码 }; LogHelper.WriteReceiveLog("支付查询-传第三方参数:【head】" + _Head.Select(pair => pair.Key + "=" + pair.Value). DefaultIfEmpty("").Aggregate((a, b) => a + "&" + b) + "【body】" + _ApiDictionary.Select(pair => pair.Key + "=" + pair.Value). DefaultIfEmpty("").Aggregate((a, b) => a + "&" + b)); //请求银行交易查询接口并返回结果 return JsonConvert.DeserializeObject( HttpUrlPost(ApiParamSign(_Head, _ApiDictionary, payConfig.PlatformKey), payConfig.ScanURL, "application/json", payConfig.PlatformTimeout)); } /// /// 贵州农信交易撤销(退款)接口 /// /// 接口配置 /// 平台商户信息 /// 平台交易订单号 /// 商户交易订单号 /// 退款订单号 /// 退款金额 /// public static Model.GZNXRefundModel PayRefund(GZNXPayConfig payConfig, MobilePayConfig.PayMerchant merchantInfo, string platformOrderCode, string merchantOrderCode, string refundOrderCode, string payAmount) { if (payConfig == null) { return default(Model.GZNXRefundModel); } if (merchantInfo == null || string.IsNullOrWhiteSpace(merchantInfo.MerchantCode)) { return default(Model.GZNXRefundModel); } if (!decimal.TryParse(payAmount, out decimal _PayAmount) || _PayAmount <= 0) { return default(Model.GZNXRefundModel); } string _SeqNo = Guid.NewGuid().ToString("N"); //生成交易退款报文头 SortedDictionary _Head = GZNXPayHead(payConfig, merchantInfo, _SeqNo, "siip_order_refund"); //生成交易退款报文体 SortedDictionary _ApiDictionary = new SortedDictionary { { "main_order_no", platformOrderCode },//行业应用平台订单号 { "ext_refund_no", refundOrderCode },//业务系统退款单号 { "term_ip", "" },//终端ip { "term_code", "0" },//终端号 { "operator", "0" },//操作员 { "refund_amt", (_PayAmount*100).ToString("F0") }, //退款金额 { "refund_reason", "" } //退款理由 }; LogHelper.WriteReceiveLog("支付退款-传第三方参数:【head】" + _Head.Select(pair => pair.Key + "=" + pair.Value). DefaultIfEmpty("").Aggregate((a, b) => a + "&" + b) + "【body】" + _ApiDictionary.Select(pair => pair.Key + "=" + pair.Value). DefaultIfEmpty("").Aggregate((a, b) => a + "&" + b)); //请求银行交易退款接口并返回结果 return JsonConvert.DeserializeObject( HttpUrlPost(ApiParamSign(_Head, _ApiDictionary, payConfig.PlatformKey), payConfig.ScanURL, "application/json", payConfig.PlatformTimeout)); } /// /// 贵州农信交易撤销查询接口 /// /// 接口配置 /// 平台商户信息 /// 商户交易订单号 /// 平台交易订单号 /// 交易金额 public static Model.GZNXRefundModel PayQueryRefund(GZNXPayConfig payConfig, MobilePayConfig.PayMerchant merchantInfo, string merchantOrderCode, string platformOrderCode, string payAmount) { if (payConfig == null) { return default(Model.GZNXRefundModel); } if (merchantInfo == null || string.IsNullOrWhiteSpace(merchantInfo.MerchantCode)) { return default(Model.GZNXRefundModel); } string _SeqNo = Guid.NewGuid().ToString("N"); //生成退款查询报文头 SortedDictionary _Head = GZNXPayHead(payConfig, merchantInfo, _SeqNo, "siip_order_result_query"); //生成退款查询报文体 SortedDictionary _ApiDictionary = new SortedDictionary { { "main_order_no", platformOrderCode },//平台订单号 { "query_type", "EXT_REFUND_NO" },//查询类型 { "query_no", merchantOrderCode }//查询号码 }; LogHelper.WriteReceiveLog("交易撤销查询-传第三方参数:【head】" + _Head.Select(pair => pair.Key + "=" + pair.Value). DefaultIfEmpty("").Aggregate((a, b) => a + "&" + b) + "【body】" + _ApiDictionary.Select(pair => pair.Key + "=" + pair.Value). DefaultIfEmpty("").Aggregate((a, b) => a + "&" + b)); //调用银行接口查询退款状态并返回结果 return JsonConvert.DeserializeObject( HttpUrlPost(ApiParamSign(_Head, _ApiDictionary, payConfig.PlatformKey), payConfig.ScanURL, "application/json", payConfig.PlatformTimeout)); } /// /// 贵州农信平台报文头公用方法 /// /// 接口配置 /// 平台商户信息 /// 交易流水号(唯一值不重复) /// 接口交易码(贵州农信提供) /// public static SortedDictionary GZNXPayHead(GZNXPayConfig payConfig, MobilePayConfig.PayMerchant merchantInfo, string merchantSeqNo, string msgCode) { //组装并返回报文头 return new SortedDictionary { { "msg_code", msgCode }, //交易码 { "seq_no", merchantSeqNo }, //流水号 { "req_time", DateTime.Now.ToString("yyyyMMddHHmmss") }, //请求时间 { "version", "3.0.1" }, //版本号 { "charset", "UTF-8" }, //字符集 { "app_id", payConfig.PlatformAPPID }, { "mercode", payConfig.Organization }, { "sign_type", payConfig.PlatformSignType }, { "sub_mercode", merchantInfo.MerchantCode } //子商户号 }; } /// /// 贵州农信支付平台签名 /// /// 报文头 /// 报文体 /// 私钥 /// public static string ApiParamSign(SortedDictionary head, SortedDictionary body, string privateKey) { //生成报文头数据字符串 string _AgwHead = JsonConvert.SerializeObject(head); //生成报文体数据字符串 string _AgwBody = JsonConvert.SerializeObject(body); //生成最终发送的数据内容 return JsonConvert.SerializeObject(new SortedDictionary> { { "AgwHead", new SortedDictionary(head) { { "signature", Sign($"head={_AgwHead}&body={_AgwBody}", privateKey) }//计算并添加签名信息 } }, { "AgwBody", new SortedDictionary(body) } }); } /// /// RSA签名方法 /// /// 待签名字符串 /// RSA私钥 /// public static string Sign(string contentForSign, string privateKey) { //转换成适用于.Net的秘钥 var netKey = RSAPrivateKeyJava2DotNet(privateKey); var rsa = new RSACryptoServiceProvider(); rsa.FromXmlString(netKey); //创建一个空对象 var rsaClear = new RSACryptoServiceProvider(); var paras = rsa.ExportParameters(true); rsaClear.ImportParameters(paras); //签名返回 using (var sha256 = new SHA256CryptoServiceProvider()) { var signData = rsa.SignData(Encoding.UTF8.GetBytes(contentForSign), sha256); return Convert.ToBase64String(signData); } } /// /// 转换Java私钥为.NET私钥 /// /// 私钥字符串 /// public static string RSAPrivateKeyJava2DotNet(string privateKey) { RsaPrivateCrtKeyParameters privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKey)); //返回.NET格式RSA私钥串 return $"{Convert.ToBase64String(privateKeyParam.Modulus.ToByteArrayUnsigned())}" + $"{Convert.ToBase64String(privateKeyParam.PublicExponent.ToByteArrayUnsigned())}" + $"

{Convert.ToBase64String(privateKeyParam.P.ToByteArrayUnsigned())}

" + $"{Convert.ToBase64String(privateKeyParam.Q.ToByteArrayUnsigned())}" + $"{Convert.ToBase64String(privateKeyParam.DP.ToByteArrayUnsigned())}" + $"{Convert.ToBase64String(privateKeyParam.DQ.ToByteArrayUnsigned())}" + $"{Convert.ToBase64String(privateKeyParam.QInv.ToByteArrayUnsigned())}" + $"{Convert.ToBase64String(privateKeyParam.Exponent.ToByteArrayUnsigned())}
"; } #region 方法 -> HttpUrlPost /// /// HttpUrlPost方法(支持HTTPS) /// /// /// /// /// /// public static string HttpUrlPost(string postData, string requestUrl, string contentType = "application/json", int timeout = 0) { try { //SSL证书验证设置 ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult); ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | (SecurityProtocolType)0x300 //Tls11 | (SecurityProtocolType)0xC00; //Tls12 //创建HTTP请求实例 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUrl); if (timeout > 0) { request.Timeout = timeout * 1000;//设置连接超时等待时间 } request.Method = "POST";//使用POST模式进行请求 request.KeepAlive = false; request.ContentType = contentType;//设置HTTP请求标头 CookieContainer cookieContainer = new CookieContainer(); request.CookieContainer = cookieContainer; byte[] postBytes = Encoding.UTF8.GetBytes(postData); request.ContentLength = postBytes.Length; //发送请求数据至指定服务 using (System.IO.Stream reqStream = request.GetRequestStream()) { reqStream.Write(postBytes, 0, postBytes.Length); } using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { //在这里对接收到的页面内容进行处理 //直到request.GetResponse()程序才开始向目标网页发送post请求 System.IO.Stream responseStream = response.GetResponseStream(); System.IO.StreamReader reader = new System.IO.StreamReader(responseStream, Encoding.GetEncoding("utf-8")); string val = reader.ReadToEnd(); return val; } } catch (Exception ex) { return ex.Message; } } private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors) { return true; } #endregion } }