1.概念普及

一、理解什么是UnionPay、ChinaPay

这两个概念如果搞不清楚,绝对够你瞎折腾一段时间的。

UnionPay:中国银联,最大的机构;他本身也提供系统接口但都是B2B的,对于单个商户他们不提供客服,也不提供技术解决,更不会提供商户后台(可查消费记录等);但他的技术接口文档比较齐全,而且也可以使用,警惕不要使用这些接口。

ChinaPay:银联电子支付公司,第三方的支付公司,UnionPay的所有接口和服务都托管给类似的第三方公司,ChinaPay再向商户服务,ChinaPay有自己的接口标准,但是非常不完善,目前只有java版本的案例;并且从UnionPay官网开通商户后,默认根据地区会自动转到诸如“ChinaPay”这样的第三方支付公司,后面的事情全由ChinaPay代管。

2.ChinaPay商户后台

开通商户之后,一般销售会发送邮件给你,一般邮件内容包含开户名称、技术支持联系方式等,另附带一个压缩包,主要包括如下内容:

txt:登录账号信息

cp.cer:加密公钥

NetPayClient:.Net的组件和properity配置文件

doc:接口文档等

logo:按钮的标准图片

3.登录ChinaPay商户后台获取交易证书

http://merchant.chinapay.com ,建议用IE或者FireFox登录,需要先下载和安装证书,安装ActiveX控件,登录证书只提供两份,多余两份的请联系销售;

登录成功之后可以看到订单、退款单等账单;

要实现支付接口,必须先获取一个“交易证书

点击交易申请证书,获取到证书之后,需要将证书的上传回商户后台,同时本地需要导出证书私钥(带密码),以备用。

4.RSA公钥私钥加密

本地商城等和ChinaPay接口通信的时候都需要对数据进行加密和验证有效性。这里就牵扯加密的知识了。

RSA公钥私钥知识只需要记住下面这三点即可

1.一个端有公钥和私钥两个文件(或者两个字符串),通信时候可以用公钥或者私钥加密

2.公钥加密数据发送,私钥解密:保证信息的完整性和保密性,保证加密后的信息第三方劫持后无法查看内容,例如邮件等。

3.私钥加密数据发送,公钥解密:保证数据来源可靠,对信息进行签名,chinapay即使利用此方式,常用于公告、群发等操作。

5.准备工作

将NetPayClient文件的dll引用到你的项目,在程序里创建一个chinapay的文件夹,放入ChinaPay的公钥(cp.cer)、私钥(交易证书导出的pfx文件,有密码),以及security.properties文件

security.properties,打开修改具体的cer、pfx文件的路径以及私钥密码

6.付款流程

跟其他产品一样,根据参数构造一个form,然后提交到目标url中,提交同时加入签名。

       log.Debug("开始支付...");string payUrl = "https://payment.chinapay.com/CTITS/service/rest/page/nref/000000000017/0/0/0/0/0";Hashtable myMap = new Hashtable();myMap.Add("MerId", ChinaPayHelper.merchantCode);string billNO = "CO" + DateTime.Now.ToString("yyyyMMddHHmmssfff");myMap.Add("MerOrderNo", billNO);myMap.Add("TranDate", DateTime.Now.ToString("yyyyMMdd"));//交易日期myMap.Add("TranTime", DateTime.Now.ToString("HHmmss"));//交易时间myMap.Add("OrderAmt", "20");myMap.Add("TranType", "0001");myMap.Add("BusiType", "0001");myMap.Add("MerPageUrl", Request.Url.Scheme + "://" + Request.Url.Authority + "/Home/PayResult");myMap.Add("MerBgUrl", Request.Url.Scheme + "://" + Request.Url.Authority + "/Home/PayBackRcv");myMap.Add("CurryNo", "CNY");myMap.Add("PayTimeOut", "145");myMap.Add("Version", "20140728");myMap.Add("CommodityMsg", "ChinaPay测试-商品信息");myMap.Add("MerResv", "ChinaPay测试-商户保留域");//myMap.Add("TranReserved", "{\"Referred\":\"www.chinapay.com\",\"BusiId\":\"0001\",\"TimeStamp\":\"1438915150976\",\"Remoteputr\":\"172.16.9.44\"}");  /***********************///坑1:这里注意,如果采用chinpay自带的签名,必须在服务器的浏览器上获取交易私钥,否则由开发环境转到生产环境会出错!!!此坑注意//chinapaysecure.SecssUtil su = new chinapaysecure.SecssUtil();//string path = Server.MapPath("/cer/security.properties");//log.Debug(path);//bool flag = su.init(path);//su.sign(myMap);//if ("00" != su.getErrCode())//{//    log.Error(su.getErrCode() + "=" + su.getErrMsg());//    ViewBag.ChinaPay = "签名过程发生错误,错误信息为-->" + su.getErrMsg();//    return View();//}//myMap.Add("Signature", su.getSign());/*******************************************///以下为采用自己扩展的签名方法,无需关心测试还是生产环境的问题!!!string signValue = ChinaPayHelper.Sign(myMap);myMap.Add("Signature", signValue);string sHtmlText = ChinaPayHelper.BuildRequest(myMap, payUrl);Response.Write(sHtmlText);

支付成功,前后台通知页面

//同步通知方法public ActionResult PayResult(){NameValueCollection coll = Request.Form;string[] requestItem = coll.AllKeys;Hashtable myMap = new Hashtable();for (int i = 0; i < requestItem.Length; i++){myMap.Add(requestItem[i], Request.Form[requestItem[i]]);//前台方法接收参数无需UrlDecode,但异步方法必须转换}SecssUtil su = new SecssUtil();su.init(Server.MapPath("/ChinaPay/CERS/security.properties"));su.verify(myMap);string billNo = myMap["MerOrderNo"].ToString();string billId = myMap["MerResv"].ToString();if ("00" != su.getErrCode()){log.Error("ChinaPayReturn银联支付返回数据验证失败:" + billNo + ";" + billId + ";" + su.getErrCode() + su.getErrMsg());ViewBag.ChinaPayResult = "ChinaPayReturn银联支付返回数据验证失败";return View();}StringBuilder sbHtml = new StringBuilder();sbHtml.Append("<table>");foreach (DictionaryEntry de in myMap){sbHtml.Append("<tr><td>" + de.Key.ToString() + "</td><td>" + Server.UrlDecode(de.Value.ToString()) + "</td></tr>");}sbHtml.Append("</table>");ViewBag.ChinaPayResult=sbHtml.ToString();return View();}//异步后台方法,用于接收支付成功和退款成功的通知[HttpPost]public void PayBackRcv(){NameValueCollection coll = Request.Form;string[] requestItem = coll.AllKeys;Hashtable myMap = new Hashtable();for (int i = 0; i < requestItem.Length; i++){log.Debug(requestItem[i] + "=" + HttpUtility.UrlDecode(Request.Form[requestItem[i]]));myMap.Add(requestItem[i], HttpUtility.UrlDecode(Request.Form[requestItem[i]]));//需要UrlDecode,否则验签失败!!!}SecssUtil su = new SecssUtil();su.init(Server.MapPath("/ChinaPay/CERS/security.properties"));su.verify(myMap);string billNo = myMap["MerOrderNo"].ToString();string billId = myMap["MerResv"].ToString();if ("00" != su.getErrCode()){log.Error("ChinaPayNotify银联支付返回数据验证失败:" + billNo + ";" + billId + ";" + su.getErrCode() + su.getErrMsg());Response.Write("fail");return;}//处理您的业务逻辑//END}

异步方法无需返回特定的code给chinapay,chinapay是根据httpstatus判断的,如果是200,都认为收到消息了。

坑2:如果出现签名失败,需要添加注册表权限,一般本机测试用管理员打开vs不存在这个问题,部署到服务器之后需要加权限

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\eventlog
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\eventlog\Security

对这两条加入Network service的读写权限。

之后可以在Window日志中调试支付中碰到的问题了。

7. 退款
string cpRefundUrl = "https://payment.chinapay.com/CTITS/service/rest/forward/syn/000000000065/0/0/0/0/0";Hashtable myMap = new Hashtable();myMap.Add("MerId", ChinaPayHelper.merchantCode);myMap.Add("MerOrderNo", "RO"+DateTime.Now.ToString("yyyyMMddHHmmssfff"));myMap.Add("TranDate", DateTime.Now.ToString("yyyyMMdd"));//交易日期myMap.Add("TranTime", DateTime.Now.ToString("HHmmss"));//交易时间myMap.Add("OriOrderNo", "20151010152643514");//改成单号myMap.Add("OriTranDate", "20151010");myMap.Add("RefundAmt", "10");//myMap.Add("OrderAmt", "10");myMap.Add("TranType", "0401");myMap.Add("BusiType", "0001");myMap.Add("MerResv", Guid.NewGuid().ToString());myMap.Add("MerBgUrl", Request.Url.Scheme + "://" + Request.Url.Authority + "/Home/PayBackRcv");myMap.Add("CurryNo", "CNY");myMap.Add("Version", "20140728");string param = ChinaPayHelper.sort(myMap, null);String chkValue = ChinaPayHelper.Sign(myMap);myMap.Add("Signature", chkValue);param += "&Signature=" + HttpUtility.UrlEncode(chkValue);log.Debug("银联退款:" + param);string rst = ChinaPayHelper.Post(cpRefundUrl + "?" + param, "");log.Debug(rst);Hashtable rstMap = ChinaPayHelper.Str2HashMap(rst);if ("0000,1022,1003".Contains(rstMap["respCode"].ToString())){return View(("[" + rstMap["respCode"].ToString() + "-" + rstMap["respMsg"].ToString() + "] 银联退款已提交,退款成功后将自动返回钱款到客户银联卡!"));}else{return View(("[" + rstMap["respCode"].ToString() + "-" + rstMap["respMsg"].ToString() + "] 银联退款失败!"));}

注意修改原始单号和原始交易日期以及退款金额:

myMap.Add("OriOrderNo", "20151010152643514");//改成单号
myMap.Add("OriTranDate", "20151010");
myMap.Add("RefundAmt", "10");

一般退款会在24小时内完成
8.退款没有异步通知???

真碰到过,联系客服之后,说是接口问题,他们修复好了之后便正常了,所以如果遇到什么问题,实在解决不了,赶紧电话客服,chinapay不是那么靠谱的。。。。!!!

9.自己封装的工具类,除了sign是override官方的,其他都是官方源文件里复制除了的方法,部分方法值得优化哦
using chinapaysecure;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Web;
/******jackchainjackchain@chinacloudtech.com2015-10-08*****/namespace ZPS.Tools
{public class ChinaPayHelper{#region 基础配置public static string merchantCode = "481601509175565"; //商户号private static string privateKeyPath = "/ChinaPay/CERS/donoratico.pfx"; //私钥文件地址private static string privateKeyPwd = "byby1231818";                    //私钥密码#endregion/// <summary>/// 签名,注意官方给出的签名方法,要求私钥必须是安装在服务器的,假若安装在本地测试机器上,等发布到生产环境中后会出现证书无法使用的错误/// </summary>/// <param name="param">需要加密的字符串</param>/// <returns></returns>public static string Sign(Hashtable myMap){string param = sort(myMap, null);X509Certificate2 certificate = new X509Certificate2(System.Web.HttpContext.Current.Server.MapPath(privateKeyPath), privateKeyPwd, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);RSAParameters key = ((RSACryptoServiceProvider)certificate.PrivateKey).ExportParameters(true);return Convert.ToBase64String(HashAndSignBytes(Encoding.UTF8.GetBytes(param), key));}/// <summary>/// 构造提交表单/// </summary>/// <param name="myMap"></param>/// <param name="actionUrl"></param>/// <returns></returns>public static string BuildRequest(Hashtable myMap, string actionUrl){StringBuilder sbHtml = new StringBuilder();sbHtml.Append("<form id='cpsubmit' name='cpsubmit' action='" + actionUrl + "' method='POST'>");foreach (DictionaryEntry de in myMap){sbHtml.Append("<input type='hidden' name='" + de.Key.ToString() + "' value='" + de.Value.ToString() + "'/>");}//submit按钮控件请不要含有name属性sbHtml.Append("<input type='submit' value='CHINAPAY' style='display:none;'></form>");sbHtml.Append("<script>document.forms['cpsubmit'].submit();</script>");return sbHtml.ToString();}/// <summary>/// 调用远程Restful服务/// </summary>/// <param name="url">url地址</param>/// <param name="param">参数</param>/// <param name="time">超时时间</param>/// <returns></returns>public static string Post(string url, string param, int time = 60000){Uri address = new Uri(url);HttpWebRequest request = WebRequest.Create(address) as HttpWebRequest;request.Method = "POST";request.ContentType = "application/json;charset=utf-8"; //"application/x-www-form-urlencoded";request.Timeout = time;byte[] byteData = UTF8Encoding.UTF8.GetBytes(param == null ? "" : param);request.ContentLength = byteData.Length;using (Stream postStream = request.GetRequestStream()){postStream.Write(byteData, 0, byteData.Length);}string result = "";using (HttpWebResponse response = request.GetResponse() as HttpWebResponse){StreamReader reader = new StreamReader(response.GetResponseStream());result = reader.ReadToEnd();}return (result);}/// <summary>/// 银联应答参数转换为哈希表/// </summary>/// <param name="param"></param>/// <returns></returns>public static Hashtable Str2HashMap(string param){string[] kv = param.Split('&');Hashtable map = new Hashtable();foreach (string str in kv){string[] temp = str.Split('=');if (temp != null && temp.Length >= 2){map.Add(temp[0], temp[1]);}}return map;}#region 以下方法ChinaPayprivate static byte[] HashAndSignBytes(byte[] DataToSign, RSAParameters Key){try{RSACryptoServiceProvider provider = new RSACryptoServiceProvider();provider.ImportParameters(Key);return provider.SignData(DataToSign, new SHA512CryptoServiceProvider());}catch (CryptographicException exception){Console.WriteLine(exception.Message);return null;}}public static string sort(Hashtable paramHashTable, string[] invalidList){IDictionaryEnumerator enumerator = paramHashTable.GetEnumerator();ArrayList list = new ArrayList();while (enumerator.MoveNext()){string str = enumerator.Key.ToString();enumerator.Value.ToString();if (((invalidList == null) || (invalidList.Length <= 0)) || !invalidList.Contains<string>(str)){list.Add(str);}}IComparer comparer = new myReverserClass();list.Sort(comparer);string str2 = string.Empty;for (int i = 0; i < list.Count; i++){string str3 = list[i].ToString();string str4 = paramHashTable[str3].ToString();if (i == (list.Count - 1)){str2 = str2 + str3 + "=" + str4;}else{string str5 = str2;str2 = str5 + str3 + "=" + str4 + "&";}}StringBuilder builder = new StringBuilder(str2);return builder.ToString();}#endregion}
}

11.总结

1.理解unionpay、chinapay可以少走很多弯路

2.理解RSA方法、警惕交易证书申请和安装,否则很可能导致测试环境能用、正式环境无法sign

3.服务器注册表权限,EventLog需要添加IIS权限

4.多问客服

一个不小的支付公司,却没有全语言的demo,真是悲哀,只好贡献一个.Net的了(MVC)下载demo http://download.csdn.net/detail/ovenj/9186317

UnionPay,ChinaPay 最新 银联支付接口C#\Asp.net\MVC 版本相关推荐

  1. Chinapay 银联支付接口

    银联开发必须要开启mcrypt 和 bcmath 两个PHP扩展库的支持 如果没有就没有办法进行开发,先确认数据库是否开启扩展 关于银联支付接口 最主要的是银行提供的秘钥和私钥, netpayclie ...

  2. php银联支付接口 demo,php版银联支付接口开发简单实例详解

    这篇文章主要介绍了php版银联支付接口开发的方法,结合实例形式分析了php银联支付接口开发的具体流程与相关操作技巧,需要的朋友可以参考下 支付接口现在有第三方的支付接口也有银行的支付接口.这里就来介绍 ...

  3. django2.0调用银联支付接口实现银联支付

    准备工作: 1.银联技术开放平台注册:https://open.unionpay.com/tjweb/acproduct/list?apiservId=448 2.点击网关支付 --> 我要测试 ...

  4. php最新银联支付chinaPay,最新接口地址

    需要下载这2个文件 再拿到公钥和秘钥 netpayclient_config.php netpayclient.php 目录结构 : 核心代码ChinaPay.php: <?phpheader( ...

  5. chinapay 新版php接口,php最新银联支付chinaPay,最新接口地址

    需要下载这2个文件 再拿到公钥和秘钥 netpayclient_config.php netpayclient.php 目录结构 : 核心代码ChinaPay.php: header('Content ...

  6. php支付接口验签,银联支付接口开发php版

    官方文档:https://open.unionpay.com/ajweb/help/file/techFile?productId=1 api辅助工具:https://open.unionpay.co ...

  7. 对接银联支付接口详解java版mac开发

    首先,这是一篇工具类的文章了,也是为了备忘,需求就是微信公众号的开发后台对接支付,有银联,支付宝,微信等,我负责写银联的接口.明天大年三十,今天在公司码完字也要灰走了,祝大家新年快乐,发大财. 先说一 ...

  8. 第三方银联支付接口对接_聊聊三方支付对接那点事儿(附Demo)

    每一个做过支付对接的少年上辈子都是折翼的天使.--题记 三方支付对接是一件比较有意思的事儿,今天就拿这个话题来掰扯掰扯.相信每个做过支付对接的小伙伴都有段血与火的经历,那段日子只有痛苦与煎熬,恨不得大 ...

  9. 小程序调银联支付接口

    这几天接了一个需求,将之前的项目支付接口改成银联的支付接口,简单说一下,对于没有接触过支付的小伙伴可能会有那么一丢丢启发- 环境:微信小程序+银联支付 文档:公司提供的开发文档+银联官方文档 框架:D ...

最新文章

  1. HiveDuino开发套件
  2. SpringBoot 2.x 整合Lombok
  3. mysql中如何删除多个表格_mysql怎么批量删除多个表?
  4. Android下实现GPS定位服务
  5. oracle11g安装和基本的使用,手把手看图教你用起来。
  6. html使用element ui_Kendo UI for jQuery使用教程:自定义小部件(二)
  7. JavaScript高级程序设计读书笔记(一)
  8. 干货!英语常用口语1000句大全(完整版)!
  9. TIMESTEN安装配置指南-中文版
  10. 从苏宁电器到卡巴斯基(第二部)第08篇:我在卡巴的日子 VIII
  11. 解决问题:RuntimeError: the sip module implements API v11.0 to v11.2 but the module requires API v12.0
  12. JavaScript定义注册页面
  13. 从程序员角度看心理学中的恐慌区、学习区和舒适区
  14. 智慧高速建设的探索与思考【附PPT】
  15. 快递账单管理线上化教程
  16. matlab 对曲线积分,matlab计算曲线积分并画出积分曲线
  17. python输入班级姓名_python,寻找班级里面名字最长的人
  18. PyCharm - 码云(Gitee)
  19. 如何使营销变得年轻化
  20. HCL打开显示当前系统用户怎么解决_软网推荐:小工具解决日常工作大问题

热门文章

  1. 2020iPadAir(第四代)对比iPadPro(第二代)
  2. Python 伪开发者对于搜狐云景的测评
  3. 蓝桥杯真题 数列求值(超范围)(好好审题啊喂)
  4. vivo联合天猫超品日共同打造X70系列城市影像馆
  5. NEUQ—ACM实验班2.4小测试反思总结
  6. Python3 bs4 + requests 简单的爬虫 爬取LOL胜率加点
  7. 家用双wan口路由器推荐_什么路由器有两个以太口 家用双wan口路由器推荐
  8. spring 事务提交成功后,再去发送事件
  9. 学习廖雪峰Git入门教程--总结
  10. iqooneo3 如何不用vivo账号下载外部应用_iQOO Neo3上手体验:软硬件结合的极致游戏体验,真香旗舰无疑...