首先吐槽下,民生支付真心坑爹、坑爹、坑爹。如果有下辈子,肯定不会接民生支付。
言归正传,首先先去官方demo里下载c#接口demo文档。地址:https://wxpay.cmbc.com.cn/cmbcpaydoc/downIndex.jsp
在程序文件夹下找到你需要的dll,dll分x64和x86,根据你项目系统版本选择对应的dll。本人这里引用的是x86dll。
1.把dll复制到项目中,文件属性设置为始终复制。
2.下面就开始写一些支付代码,主要从demo中提取。(注:民生demo里面方法杂合在一起,要把方法分开来),这里我就不贴demo代码了,直接贴我整合过的代码。
[DllImport("SADK.CMBC.x86.dll")] //[DllImport("SADK.CMBC.x64.dll")] public static extern int Initialize(); [DllImport("SADK.CMBC.x86.dll")] //[DllImport("SADK.CMBC.x64.dll")] public static extern int Uninitialize(); [DllImport("SADK.CMBC.x86.dll")] //[DllImport("SADK.CMBC.x64.dll")] public static extern int SignData_PKCS1(string pszAlgorithm, byte[] pbySourceData, int nSourceSize, string pszPFXFilePath, string pszPFXPassword, string pszHashAlg, ref IntPtr ppszBase64PKCS1Signature); [DllImport("SADK.CMBC.x86.dll")] //[DllImport("SADK.CMBC.x64.dll")] public static extern int VerifyDataSignature_PKCS1(string pszAlgorithm, byte[] pbySourceData, int nSourceSize, string pszBase64CertContent, string pszHashAlg, string pszBase64PKCS1Signature); [DllImport("SADK.CMBC.x86.dll")] //[DllImport("SADK.CMBC.x64.dll")] public static extern int SetZvalueFlag(int IsWithZValue); [DllImport("SADK.CMBC.x86.dll")] //[DllImport("SADK.CMBC.x64.dll")] public static extern int EncryptDataToCMSEnvelope(string pszAlgorithm, byte[] pbyPlainData, int nPlainDataSize, string pszBase64CertContent, string pszSymEncAlg, ref IntPtr ppszBase64CMSEnvelope); [DllImport("SADK.CMBC.x86.dll")] //[DllImport("SADK.CMBC.x64.dll")] public static extern int DecryptDataFromCMSEnvelope(string pszAlgorithm, string pszBase64CMSEnvelope, string pszPFXFilePath, string pszPFXPassword, ref IntPtr ppbyPlainData, ref int pnPlainDataSize); [DllImport("SADK.CMBC.x86.dll")] //[DllImport("SADK.CMBC.x64.dll")] public static extern void FreeMemory(IntPtr ptrBuf); /// <summary> /// 一码付 /// </summary> /// <param name="merchantSeq">订单流水</param> /// <returns></returns> public string doYardPay(string merchantSeq) { //根据订单号查询订单信息 PayOrderDomain payOrderDomain = new PayOrderDomain(); PAY_Order parOrder = new PAY_Order(); List<PAY_Order> payOrderList = payOrderDomain.GetByOrderNoList(merchantSeq); if (payOrderList != null && payOrderList.Count > 0) { parOrder = payOrderList.First(); } else { return "Order does not exist"; } decimal amount = decimal.Multiply((decimal)parOrder.Amount, (decimal)100); amount = 1; // 拼接请求参数 string strContext = "";
// 官方提供的支付地址 var payUrl = YardPadConfig.PayUrl; string plateFormId = YardPadConfig.PlateFormId; string merchantNum = YardPadConfig.MerchantNo; string signStr = "&amount=" + amount + "&merchantNum=" + merchantNum + "&merchantSeq=" + newOrderNo + "&platformId=" + plateFormId; // 获取签名 string sign = Sign(signStr); if (!String.IsNullOrEmpty(sign)) { // 生成二维码地址 strContext = payUrl + signStr + "&sign=" + sign; } return strContext; } /// <summary> /// 交易查询 /// </summary> /// <param name="merchantSeq">订单号</param> /// <param name="sysId">系统id</param> /// <returns></returns> public void PayQuery(string merchantSeq, string systemCode) { PayOrderDomain payOrderDomain = new PayOrderDomain(); PAY_Order payOrder = new PAY_Order(); List<PAY_Order> payOrderLists = payOrderDomain.GetList(merchantSeq, systemCode); if (payOrderLists != null && payOrderLists.Count > 0) { payOrder = payOrderLists.First(); if (!"Paied".Equals(payOrder.Status)) { // 拼接请求参数 PayQueryModel p = new PayQueryModel(); p.merchantNo = YardPadConfig.MerchantNo; p.merchantSeq = payOrder.Order_No; p.platformId = YardPadConfig.PlateFormId; p.orgvoucherNo = ""; p.reserve = ""; p.tradeType = "1"; // 1 支付 2退款 string payJson = SerializeHelper.ToJson<PayQueryModel>(p); // 获取签名 string sign = Sign(payJson); if (!String.IsNullOrEmpty(sign)) { FPayQueryModel fp = new FPayQueryModel(); fp.sign = sign; fp.body = payJson; string fpayJson = SerializeHelper.ToJson<FPayQueryModel>(fp); // 信息加密 string encrypt = Encrypt(fpayJson); // 请求地址 string queryUrl = YardPadConfig.QueryUrl; // 请求的参数json BusinessContentModel business = new BusinessContentModel(); business.businessContext = encrypt; business.merchantNo = ""; business.merchantSeq = ""; business.reserve1 = ""; business.reserve2 = ""; business.reserve3 = ""; business.reserve4 = ""; business.reserve5 = ""; business.reserveJson = ""; business.securityType = ""; business.sessionId = ""; business.source = ""; business.transCode = ""; business.transDate = ""; business.transTime = ""; business.version = ""; string param = SerializeHelper.ToJson<BusinessContentModel>(business); // 调用api string result = PostMoths(queryUrl, param); // 信息解密 ResultModel resultModel = SerializeHelper.FromJson<ResultModel>(result); if ("S".Equals(resultModel.gateReturnType)) { string decrypt = Decrypt(resultModel.businessContext); RFPayQueryModel fpayquerymodel = SerializeHelper.FromJson<RFPayQueryModel>(decrypt); RPayQueryModel payquerymodel = SerializeHelper.FromJson<RPayQueryModel>(fpayquerymodel.body); string resultSign = CheckSign(fpayquerymodel.sign, SerializeHelper.ToJson<RPayQueryModel>(payquerymodel)); // 验签 if ("0".Equals(resultSign)) {//验签成功,更新订单表状态 List<PAY_Order> payOrderList = payOrderDomain.GetByOrderNoList(payquerymodel.merchantSeq); if (payOrderList != null && payOrderList.Count > 0) { payOrder = payOrderList.First(); payOrder.Status = "Paied"; payOrder.Pay_Time = DateTime.Now; payOrder.UpdateDate = DateTime.Now; payOrderDomain.Modify(payOrder.ID, payOrder); } } } } } } } /// <summary> /// 签名 /// </summary> /// <param name="file"></param> /// <param name="signStr"></param> /// <returns></returns> public string Sign(string signStr) { int nResult = -1; // Declear Parameters //**************签名和验签测试源数据******************************// string pszAlgorithm = "SM2"; // 测试商户私钥 //string pszPFXFilePath = HttpContext.Current.Server.MapPath("~/Templates/cust0001.sm2"); // 正式商户私钥 string pszPFXFilePath = HttpContext.Current.Server.MapPath("~/Templates/xjtlu.sm2"); string pszPFXPassword = YardPadConfig.MerchantPwd; string pszHashAlg = "SM3"; string strSourceData = signStr; byte[] pbySourcddeData = System.Text.Encoding.UTF8.GetBytes(strSourceData); //string strSourceData = "abcdefg"; int nSourceSize = pbySourcddeData.Length; byte[] pbySourceData = null; IntPtr pszBase64PKCS1Signature = IntPtr.Zero; string sign = ""; nResult = Initialize(); if (0 == nResult) { Console.WriteLine("Initialize Success! \n"); } else { Console.WriteLine("Initialize FILED! \n Error code : " + nResult); goto exit; } SetZvalueFlag(1); // 对源数据签名,签名请选择签名证书 char[] cc = strSourceData.ToCharArray(); pbySourceData = System.Text.Encoding.UTF8.GetBytes(cc); nResult = SignData_PKCS1(pszAlgorithm, pbySourceData, nSourceSize, pszPFXFilePath, pszPFXPassword, pszHashAlg, ref pszBase64PKCS1Signature); if (0 == nResult) { sign = Marshal.PtrToStringAnsi(pszBase64PKCS1Signature); Console.WriteLine(sign + "-Sign Success! \n"); } else { Console.WriteLine("Sign FILED! \n Error code : " + nResult); goto exit; } exit: //释放由程序分配的内存,避免程序内存泄露 if (IntPtr.Zero != pszBase64PKCS1Signature) { FreeMemory(pszBase64PKCS1Signature); } // 当不再使用工具包时,调用Uninitialize函数反初始化工具包 nResult = Uninitialize(); if (0 == nResult) { Console.WriteLine("Uninitialize Success! \n"); } else { Console.WriteLine("Uninitialize FILED! \n Error code : " + nResult); } //Console.Read(); return sign; } /// <summary> /// 加密 /// </summary> /// <param name="json"></param> /// <returns></returns> public string Encrypt(string json) { int nResult = -1; //******************加密和解密测试源示例**********************// string pszEncryptAlgorithm = "SM2"; // 测试民生公钥 //string file = HttpContext.Current.Server.MapPath("~/Templates/cmbcTest.cer"); // 正式民生公钥 string file = HttpContext.Current.Server.MapPath("~/Templates/cmbc.cer"); //string pszBase64CertEncryptContent = ReadFile(file); // 取公钥的值 去掉首尾的注释 string pszBase64CertEncryptContent = "MIIClzCCAjugAwIBAgIFECYUJxAwDAYIKoEcz1UBg3UFADAlMQswCQYDVQQGEwJDTjEWMBQGA1UECgwNQ0ZDQSBTTTIgT0NBMTAeFw0xNTAzMjYwNjEwMzFaFw0yMDAzMjYwNjEwMzFaMIGDMQswCQYDVQQGEwJDTjESMBAGA1UECgwJQ0ZDQSBPQ0ExMQ0wCwYDVQQLDARDTUJDMRkwFwYDVQQLDBBPcmdhbml6YXRpb25hbC0xMTYwNAYDVQQDDC0wMzA1QDcxMDAwMTg5ODhA5Lqk5piT6ZO26KGMUDJQ6LWE6YeR5omY566hQDEwWTATBgcqhkjOPQIBBggqgRzPVQGCLQNCAAQ24zsOiNcNELoSdqCtX2Kn0ppIJUZ22WmKcU7Payx0M7tpXY2p6OZUaAzDkPr / Kc4pnTAnMNw4ySuFn5nuxHymo4H2MIHzMB8GA1UdIwQYMBaAFFyTWCBaJHNWEBtkUBDs6afKB0ERMAwGA1UdEwQFMAMBAQAwSAYDVR0gBEEwPzA9BghggRyG7yoBATAxMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmNmY2EuY29tLmNuL3VzL3VzLTE0Lmh0bTA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmNmY2EuY29tLmNuL1NNMi9jcmwxMTQwLmNybDALBgNVHQ8EBAMCA + gwHQYDVR0OBBYEFBA91H5B / osNLL3dY4BB13cjLl / 2MBMGA1UdJQQMMAoGCCsGAQUFBwMCMAwGCCqBHM9VAYN1BQADSAAwRQIgOIofwSmSbkSu5jJw17o + X7JKcH / NpX + PUvlss7le2XUCIQCGHTGqr76HdqCX0ukkt7ORmpmepcTpDG5ng9QW4DqtAw =="; pszBase64CertEncryptContent = pszBase64CertEncryptContent.Trim(); string pszSymEncAlg = "SM4"; // Declear Parameters string strSourceData = json; byte[] pbySourcddeData = System.Text.Encoding.UTF8.GetBytes(strSourceData); //string strSourceData = "abcdefg"; int nSourceSize = pbySourcddeData.Length; IntPtr pszBase64CMSEnvelope = IntPtr.Zero; string strBase64CMSEnvelope = ""; string cipher = ""; nResult = Initialize(); if (0 == nResult) { Console.WriteLine("Initialize Success! \n"); } else { Console.WriteLine("Initialize FILED! \n Error code : " + nResult); goto exit; } //********************加密数字信封*********************// char[] cc = strSourceData.ToCharArray(); pbySourcddeData = System.Text.Encoding.UTF8.GetBytes(cc); //int nSourceSize2 = pbySourcddeData.Length; nResult = EncryptDataToCMSEnvelope(pszEncryptAlgorithm, pbySourcddeData, nSourceSize, pszBase64CertEncryptContent, pszSymEncAlg, ref pszBase64CMSEnvelope); if (0 == nResult) { cipher = Marshal.PtrToStringAnsi(pszBase64CMSEnvelope); Console.WriteLine(cipher + " EncryptDataToCMSEnvelope Success! \n"); Console.WriteLine("EncryptDataToCMSEnvelope Success! \n"); } else { Console.WriteLine("EncryptDataToCMSEnvelope FILED! \n Error code : " + nResult); goto exit; } strBase64CMSEnvelope = Marshal.PtrToStringAnsi(pszBase64CMSEnvelope); FreeMemory(pszBase64CMSEnvelope); pszBase64CMSEnvelope = IntPtr.Zero; exit: //释放由程序分配的内存,避免程序内存泄露 if (IntPtr.Zero != pszBase64CMSEnvelope) { FreeMemory(pszBase64CMSEnvelope); } // 当不再使用工具包时,调用Uninitialize函数反初始化工具包 nResult = Uninitialize(); if (0 == nResult) { Console.WriteLine("Uninitialize Success! \n"); } else { Console.WriteLine("Uninitialize FILED! \n Error code : " + nResult); } //Console.Read(); return strBase64CMSEnvelope; } /// <summary>/// 解密 /// </summary> /// <param name="strBase64CMSEnvelope">加密信息</param> /// <returns></returns> public string Decrypt(string strBase64CMSEnvelope) { int nResult = -1; string strSourceDatanew = ""; //******************加密和解密测试源示例**********************// string pszEncryptAlgorithm = "SM2"; // 测试商户私钥 //string pszEncryptPFXFilePath = HttpContext.Current.Server.MapPath("~/Templates/cust0001.sm2"); // 正式商户私钥 string pszEncryptPFXFilePath = HttpContext.Current.Server.MapPath("~/Templates/xjtlu.sm2"); string pszEncryptPFXPassword = YardPadConfig.MerchantPwd; // Declear Parameters IntPtr pbyDecryptPlainData = IntPtr.Zero; int nDecryptPlainDataSize = 0; nResult = Initialize(); if (0 == nResult) { Console.WriteLine("Initialize Success! \n"); } else { Console.WriteLine("Initialize FILED! \n Error code : " + nResult); goto exit; } //***********************解密数字信封*************************// nResult = DecryptDataFromCMSEnvelope(pszEncryptAlgorithm, strBase64CMSEnvelope, pszEncryptPFXFilePath, pszEncryptPFXPassword, ref pbyDecryptPlainData, ref nDecryptPlainDataSize); byte[] pbyDecryptSourceData = new byte[nDecryptPlainDataSize]; Marshal.Copy(pbyDecryptPlainData, pbyDecryptSourceData, 0, nDecryptPlainDataSize); strSourceDatanew = System.Text.Encoding.UTF8.GetString(pbyDecryptSourceData); //strSourceData = Marshal.PtrToStringAnsi(pbyDecryptPlainData); FreeMemory(pbyDecryptPlainData); pbyDecryptPlainData = IntPtr.Zero; if (0 == nResult) { Console.WriteLine(strSourceDatanew + "-DecryptDataFromCMSEnvelope Success! \n"); } else { Console.WriteLine("DecryptDataFromCMSEnvelope FILED! \n Error code : " + nResult); goto exit; } exit: //释放由程序分配的内存,避免程序内存泄露 if (IntPtr.Zero != pbyDecryptPlainData) { FreeMemory(pbyDecryptPlainData); } // 当不再使用工具包时,调用Uninitialize函数反初始化工具包 nResult = Uninitialize(); if (0 == nResult) { Console.WriteLine("Uninitialize Success! \n"); } else { Console.WriteLine("Uninitialize FILED! \n Error code : " + nResult); } //Console.Read(); return strSourceDatanew; } /// <summary> /// 验签 /// </summary> /// <param name="strBase64PKCS1Signature">签名</param> /// <param name="json">签名以外的参数</param> /// <returns></returns> public string CheckSign(string strBase64PKCS1Signature, string json) { int nResult = -1; // Declear Parameters //**************签名和验签测试源数据******************************// string pszAlgorithm = "SM2"; string pszHashAlg = "SM3"; // 测试商户公钥 //string file = HttpContext.Current.Server.MapPath("~/Templates/cust0001.cer"); // 正式民生公钥 string file = HttpContext.Current.Server.MapPath("~/Templates/cmbc.cer"); string pszBase64CertContent = ReadFile(file); string strSourceData = json; byte[] pbySourcddeData = System.Text.Encoding.UTF8.GetBytes(strSourceData); //string strSourceData = "abcdefg"; int nSourceSize = pbySourcddeData.Length; byte[] pbySourceData = null; nResult = Initialize(); if (0 == nResult) { Console.WriteLine("Initialize Success! \n"); } else { Console.WriteLine("Initialize FILED! \n Error code : " + nResult); goto exit; } // 对源数据签名,签名请选择签名证书 char[] cc = strSourceData.ToCharArray(); pbySourceData = System.Text.Encoding.UTF8.GetBytes(cc); // 验签 nResult = VerifyDataSignature_PKCS1(pszAlgorithm, pbySourceData, nSourceSize, pszBase64CertContent, pszHashAlg, strBase64PKCS1Signature); if (0 == nResult) { Console.WriteLine("Verify Success! \n"); } else { Console.WriteLine("Verify FILED! \n Error code : " + nResult); goto exit; } exit: // 当不再使用工具包时,调用Uninitialize函数反初始化工具包 nResult = Uninitialize(); if (0 == nResult) { Console.WriteLine("Uninitialize Success! \n"); } else { Console.WriteLine("Uninitialize FILED! \n Error code : " + nResult); } //Console.Read(); return "" + nResult; } /// <summary> /// post请求 /// </summary> /// <param name="url"></param> /// <param name="param"></param> /// <returns></returns> public string PostMoths(string url, string param) { string strURL = url; System.Net.HttpWebRequest request; request = (System.Net.HttpWebRequest)WebRequest.Create(strURL); request.Method = "POST"; request.ContentType = "application/json;charset=UTF-8"; string paraUrlCoded = param; byte[] payload; payload = System.Text.Encoding.UTF8.GetBytes(paraUrlCoded); request.ContentLength = payload.Length; Stream writer = request.GetRequestStream(); writer.Write(payload, 0, payload.Length); writer.Close(); System.Net.HttpWebResponse response; response = (System.Net.HttpWebResponse)request.GetResponse(); System.IO.Stream s; s = response.GetResponseStream(); string StrDate = ""; string strValue = ""; StreamReader Reader = new StreamReader(s, Encoding.UTF8); while ((StrDate = Reader.ReadLine()) != null) { strValue += StrDate + "\r\n"; } return strValue; }
/// <summary> /// 读文件 /// </summary> /// <param name="path">文件路径</param> /// <returns></returns> public static string ReadFile(string Path) { try { FileStream fs = new FileStream(Path, FileMode.Open); StreamReader sr = new StreamReader(fs, Encoding.UTF8); string nextLine; string content = ""; while ((nextLine = sr.ReadLine()) != null) { if (nextLine.Contains("-----BEGIN CERTIFICATE-----") || nextLine.Contains("-----END CERTIFICATE-----")) { continue; } else content = content + nextLine; } sr.Close(); return content; } catch { return "<span style='color:red; font-size:x-large;'>Sorry,The Ariticle wasn't found!! It may have been deleted accidentally from Server.</span>"; } }
注: cmbcTest.cer 为民生银行公钥证书
cust0001.sm2 为测试商户私钥证书
cust0001.cer 为测试商户公钥证书
测试环境: 使用商户私钥签名,商户公钥加密;使用商户私钥解密,商户公钥验签。
正式环境: 签名解密用商户私钥,加密验签用民生公钥
支付回调
/// <summary> /// 一码付回调 /// </summary> /// <returns></returns> [HttpPost] public string ENotify() { string isOk = "FAILED"; byte[] byts = new byte[Request.InputStream.Length]; Request.InputStream.Read(byts, 0, byts.Length); // 获取json数据 string req = System.Text.Encoding.Default.GetString(byts);if (String.IsNullOrEmpty(req)) { return isOk; } NotifyModel notify = new NotifyModel(); notify = SerializeHelper.FromJson<NotifyModel>(req); // 解密json数据 string decStr = yardPayService.Decrypt(notify.context); RFPayQueryModel rfPayQueryModel = new RFPayQueryModel(); rfPayQueryModel = SerializeHelper.FromJson<RFPayQueryModel>(decStr); // 验证签名是否正确 string sign = yardPayService.CheckSign(rfPayQueryModel.sign, decStr); if ("0".Equals(sign)) {// 获取订单详细信息 PayNotifyModel payNotifyModel = new PayNotifyModel(); payNotifyModel = SerializeHelper.FromJson<PayNotifyModel>(rfPayQueryModel.body);//验签成功,更新订单表状态 PayOrderRelationDomain payOrderRelationDomain = new PayOrderRelationDomain(); List<PAY_Order_Relation> payOrderRelationList = payOrderRelationDomain.GetByOrderNoList(payNotifyModel.orderNo); if (payOrderRelationList != null && payOrderRelationList.Count > 0) { PAY_Order_Relation payOrderRelation = payOrderRelationList.First(); PayOrderDomain payOrderDomain = new PayOrderDomain(); PAY_Order payOrder = new PAY_Order(); List<PAY_Order> payOrderList = payOrderDomain.GetByOrderNoList(payOrderRelation.Original_Order_No); if (payOrderList != null && payOrderList.Count > 0) { payOrder = payOrderList.First(); payOrder.Status = "Paied"; payOrder.UpdateDate = DateTime.Now; payOrder.NotifyNum = 1; payOrder.NotifyTime = DateTime.Now.AddMinutes(5); payOrderDomain.Modify(payOrder.ID, payOrder); isOk = "SUCCESS"; } } } return isOk; }