2022年网银在线支付接口和应用 .pdf
网银在线支付接口和应用(转载)关键字 : 网银在线支付接口和应用最近关注项目中在线支付 , 所以看一下文档 , 在线支付应用开发 : 基本所有的在线支付均采用以下方式: 客户点击结帐时将关于訂單的信息和货币信息, 相应的信息 , 经过或其他方式发送 ( 可能和或) 支付平台( 块钱, 或支付宝等), 支付平臺处理完毕时根据相应, 返回相关的信息 (付款信息 , 訂單信息 , 验证信息 ). 在实际操作 Money的问题人们一向关注他的安全性等问题, 同时本人习惯在通过 http 方式访问非外网时采用Commons-httpclient的发送实现 , 简单方便 , 所以采用此种实现 : 具体看以下和原代码: 网银在线支付接口: 商户 网银在线支付 : 商户编号 订单编号 订单总金额 币种支付动作完成后返回到该url ,支付结果以 POST 方式发送 订单 MD5 校验码备注字段 1备注字段 2 收货人姓名 收货人地址名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 1 页,共 13 页 - - - - - - - - - 收货人电话 收货人邮编 商品信息 订货人姓名 订货人邮件MD5 校验串生成方法: 当消费者在商户端生成最终订单的时候,将订单中的v_amount v_moneytype v_oid v_mid v_url key六个参数的 value 值拼成一个无间隔的字符串 (顺序不要改变 )。参数 key 是商户的 MD5 密钥(该密匙可在登陆商户管理界面后自行更改。)网银在线支付 商户支付完成后页面转到商户,从网银在线支付返回的消息格式为: 该消息格式详细解释如下:v_url 是该笔订单提交时参数v_url 的值,即网银返回到商户的接口地址。变量名称变量命名返回值说明订单编号v_oid商户发送的 v_oid 定单编号。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 2 页,共 13 页 - - - - - - - - - 支付状态v_pstatus20(表示支付成功)30(表示支付失败)支付结果信息v_pstring支付完成支付完成支付方式v_pmode支付银行,例如工商银行订单 MD5 校验码v_md5str该参数的 MD5 字符串的顺序为: v_oid,v_pstatus ,v_amount ,v_moneytype ,key MD5 字符串示例 :20050320- 1001-000001234 2012.34 0key用 MD5 函数加密上述字符串后得到的值如果和 v_md5str值相等即表明返回的信息没有被纂改订单总金额v_amount订单实际支付金额币种v_moneytype订单实际支付币种备注字段 1remark1备注字段 2remark2表 3package .vnvtrip.china.pay.proxy;import static mons.ChinaPayConstants.CHINABANK_NOTIFY_URL_HTTP; import static mons.ChinaPayConstants.CHINABANK_PAY_HTTPS; import static mons.ChinaPayConstants.CHINABANK_PAY_MD5_KEY;import java.util.HashMap; import java.util.Map; import java.util.Properties;import mons.codec.digest.DigestUtils;import mons.Env; import mons.HTTPClient;/* * * 网银接口服务的代理 * * author longgangbai * */ public class ChinaPayProxy 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 3 页,共 13 页 - - - - - - - - - /* * 在下訂單時采用的的加密的信息: MD5 校验串生成方法: 当消费者在商户端生成最终订单的时候,将订单中的 v_amount * v_moneytype v_oid v_mid v_url key六个参数的 value值拼成一个无间隔的字符串 (顺序不要改变 )。* 参数 key是商户的 MD5 密钥 (该密匙可在登陆商户管理界面后自行更改。)* * param v_amount * param v_moneytype * param v_oid * param v_mid * param v_url * param key * return */ private static String getMd5Sign(String v_amount, String v_moneytype, String v_oid, String v_mid, String v_url, String key) StringBuffer sb = new StringBuffer(); sb.append(v_amount); sb.append(v_moneytype); sb.append(v_oid); sb.append(v_mid); sb.append(v_url); sb.append(key); byte bytes = DigestUtils.md5(sb.toString(); String md5info = new String(bytes).toUpperCase(); return md5info; /* * 调用支付网关接口网址银行结帐的接口代理(本人习惯采用-httpclient实现) * 用途:用来接受商户发给网银在线服务支付的订单信息* * param v_mid * 商户编号 (非空) * param v_oid * 订单编号 (非空)(格式:订单生成日期 ( mmdd)-商户编号 -商户流水号 )字段不可超过位* param v_amount * 订单总金额(非空) * param v_moneytype * 货币类型(非空) :美元* param v_url * (非空) 支付的动作完成时返回的该,支付结果以方式名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 4 页,共 13 页 - - - - - - - - - 发送* param v_md5info * 订单校验码* param remark1 * 备注字段 (可选字段 ) * param remark2 * 备注字段(可选字段 ) * param _vmd * mmdd 备注字段(不可为空字段 ) * param v_rcvname * 收货人姓名(自定义非网银必须字段 ) * param v_rcvaddr * 收货人地址 (自定义非网银必须字段 ) * param v_rcvtel * 收货人电话 (自定义非网银必须字段 ) * param v_rcpost * 收货人邮编 (自定义非网银必须字段 ) * param v_orderstatus * 商品信息 (自定义非网银必须字段 ) * param v_ordername * 订货人姓名 (自定义非网银必须字段 ) * param v_orderemail * 订货人邮件 (自定义非网银必须字段 ) * return */ public static boolean chinaBankPayCheck(String v_mid, String v_oid, String v_amount, String v_moneytype, String v_url, String remark1, String remark2, String v_rcvname, String v_rcvaddr, String v_rcvtel, String v_rcpost, String v_orderstatus, String v_ordername, String v_orderemail) Properties p = Env.getEnv().getProperties(); String md5key = p.getProperty(CHINABANK_PAY_MD5_KEY); String v_md5info = getMd5Sign(v_amount, v_moneytype, v_oid, v_mid, v_url, md5key); Map paramMaps = new HashMap(); paramMaps.put(v_mid, v_mid); paramMaps.put(v_oid, v_oid); paramMaps.put(v_amount, v_amount); paramMaps.put(v_moneytype, v_moneytype); paramMaps.put(v_url, p.getProperty(CHINABANK_NOTIFY_URL_HTTP); paramMaps.put(v_md5info, v_md5info); paramMaps.put(remark1, remark1); paramMaps.put(remark2, remark2); 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 5 页,共 13 页 - - - - - - - - - paramMaps.put(v_rcvname, v_rcvname); paramMaps.put(v_rcvaddr, v_rcvaddr); paramMaps.put(v_rcvtel, v_rcvtel); paramMaps.put(v_rcpost, v_rcpost); paramMaps.put(v_orderstatus, v_orderstatus); paramMaps.put(v_ordername, v_ordername); paramMaps.put(v_orderemail, v_orderemail); return HTTPClient.executeHttp(CHINABANK_PAY_HTTPS, paramMaps, null); /* * result 为支付完毕接受的结果的map 校验检测在网银支付数据是否被拦截的* * param v_oid * 获取结果中的訂單编号* param v_pstatus * 获取訂單的支付状态* param v_pstring * 支付的结果* param v_amount * 实际支付的金额* param v_moneytype * 实际支付的币种* param v_md5str * 获取訂單校验的验证* return */ public static boolean checkPayOff(String v_oid, String v_pstatus, String v_pstring, String v_amount, String v_moneytype, String v_md5str) Properties p = Env.getEnv().getProperties(); String md5key = p.getProperty(CHINABANK_PAY_MD5_KEY); String checkmd5 = getCheckMd5(v_oid, v_pstatus, v_amount, v_moneytype, md5key); if (checkmd5.equals(v_md5str) return true; return false; /* * 得到网银訂單付款后加密检查* * param v_oid 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 6 页,共 13 页 - - - - - - - - - * param v_pstatus * param v_amount * param v_moneytype * param key * return */ private static String getCheckMd5(String v_oid, String v_pstatus, String v_amount, String v_moneytype, String key) StringBuffer sb = new StringBuffer(); sb.append(v_oid); sb.append(v_pstatus); sb.append(v_amount); sb.append(v_moneytype); sb.append(key); byte bytes = DigestUtils.md5(sb.toString(); String md5info = new String(bytes).toUpperCase(); return md5info; 来自 http:/ - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 7 页,共 13 页 - - - - - - - - - 2010-02-09 建设银行对接(一)文章分类 : Java 编程这几天 项目需要对接建设银行的支付和查询功能,在支付和查询的时候将系统链接到建行指定的页面上,由于这些页面是基于互联网的,开放的,所以需要对数据加密和数字签名。我来实现这个数据加密解密模块, 功能已经完成了,唉, 不过让我晕死的是,建行其实一并提供了jar 包, 已经实现了数据加密解密,校验数字签名的功能, 只不过同事没注意到, 只发接口文档给我, 没发 jar 包给我,害我白着急了几天,不过工作也没算浪费,自己实现的还是比较放心些吧。这些页面的跳转没什么技术, 主要在于数据加密和数字签名, 在链接到建行页面之前,先将参数加密,在收到建行跳转过来的链接参数后,取出参数里的签名,将签名和原始参数进行校验, 以确认目前跳转过来的的确是建行。页面跳转没什么好说的,我所感兴趣的在于加密这些地方,以及对建行文档的理解。按照建行的规定,我们发送的数据需要进行MD5 加密,建行对返回的数据进行了数字签名,我们需要校验签名的有效性。以下是建行的两项约定:建行附录1 : MAC 算法说明Html 代码1.建设银行家居银行项目组决定对商户向网上银行系统提交的交易内容进行 MAC 校验,校验算法采用标准MD5 算法,不带密钥。 该算法的详细说明请参见 RFC 1321文档。2.3.商户实行标准的 MD5 算法对向网上银行系统提交的交易内容进行MAC校验,产生 128位(bit )的 MAC 结果。输入为字符串,输出为16 进制字符表示的字符串。4.5. 下面是对 MAC 结果的显示方式的描述:6.7. 对 128 位的交易结果按 4 位为一个单位进行划分,共获得32 段8.9. 将每段看成一个 16 进制数,如 0011 为 0X3,1101 为 0Xd。10. 11. 将这个数映射到 ASCII 码表,形成相应的字符,如0X2为“2”, 0Xd为“d”。12. 13. 将这些字符连成一个字符串,长度为32。14. 15. 16. 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 8 页,共 13 页 - - - - - - - - - 17. 下面是一些字符串进行MAC 并按上述方法进行转换后获得的结果:18. 19.MD5 () = d41d8cd98f00b204e9800998ecf8427e 20. 21.MD5 (a) = 0cc175b9c0f1b6a831c399e269772661 22. 23.MD5 (abc) = 900150983cd24fb0d6963f7d28e17f72 建行附录2 :数字签名算法说明Html 代码1.银行将客户支付信息实时通知给商户时,使用的数字签名算法是MD5withRSA 算法。商户验证签名的公钥在商户在网银系统开户,获取数字证书后,登录到网银系统中,通过下载公钥交易获取。(下载后需妥善管理并及时更新商户公钥,以防公私钥不匹配造成验签不通过)。(目前家居银行项目组采用静态密钥对,上线前生成一对, 发给合作商户。 )2.3.商户获取的公钥用X.509 格式表示,并且将其按照每4 位(bit )转换为一个 16 进制数的方式表示, 产生 16 进制的字符串。 家居银行使用标准 MD5withRSA 算法对给商户的响应进行签名,产生1024 位(bit )的签名结果,并且将其按照每4 位 (bit ) 转换为一个 16 进制数的方式表示,形成 16 进制的字符串,长度为256。4.5.6.7. 下面是对签名结果的表示方式的描述:8.9. 对 1024 位的交易结果按 4 位为一个单位进行划分,共获得256 段10. 11. 将每段看成一个 16 进制数,如 0011 为 0X3,1101 为 0Xd。12. 13. 将这个数映射到 ASCII 码表,形成相应的字符,如0X2为“2”, 0Xd为“d”。14. 15. 将这些字符连成一个字符串,长度为256。16. 17. 18. 19. 例如:20. 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 9 页,共 13 页 - - - - - - - - - 21. 待签名的字符串为:22. 23. POSID =000000000&BRANCHID=110000000&ORDERID=19991101234&PAYMENT=500.00&CURCODE=01&REMARK119991101& REMARK2=merchantname &SUCCESS=Y24. 25. 签名结果为:26. 27.4b3ef029516193b7d969ac1840083635a3e0901b8cd526caa44c1a072f496d7f0d4bca3942c0d9030bede37c7809b835cec787eb39e18b7596a724fba9805b24714dfbb0f4a3fb430b32e075254a114d4c38a0ac52ef46a0ad33dec3fbfc15417402a1399e65e46996c0cf49fc7ffca9222f8cd693c8376b6f928828967bec42 28. 29. 30. 31. 当商户收到银行传来的CGI串后,从中获取签名 (格式如上) 和需签名的原文。商户端程序(商户自行开发MD5withRSA 签名校验程序)将签名和商户端的公钥转换成二进制格式,与签名的原文一起对签名的正确性进行校验,校验步骤如下:32. 33. 使用公钥进行签名的逆运算34. 35. 使用标准 MD5 算法运算原文36. 37. 比较 1)、2)结果。仔细看上面两项约定, 无论是 MD5 加密还是RSA加密,都有一个基础工作,就是将二进制数据分割,换算成16 进制字符,还需要进行逆运算。将结果按 4 位为一个单位进行划分, 共获得 32 段, 将每段看成一个16 进制数,如0011 为 0X3 , 1101 为 0Xd 。 将这个数映射到ASCII码表,形成相应的字符,如 0X2 为“ 2 ”, 0Xd 为“ d ”。 将这些字符连成一个字符串,长度为 32 。 我先实现这个功能,代码如下:ByteUtil.java Java 代码1. package cn.ipanel.payment.business.bank.ccb.encryption; 2.3. /* 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 10 页,共 13 页 - - - - - - - - - 4. * 字节运算工具 , 其作用和背景请见建行接口文档的 附录 1: MAC 算法说明 5. * 6. * author wangxiaoxue 7. * 8. */ 9. public class ByteUtil 10. / 用来将字节转换成 16 进制表示的字符11. private static char hexDigits = 0, 1, 2, 3, 4, 5, 6, 7, 12. 13. 8, 9, a, b, c, d, e, f ; 14. 15. /* 16. * 找到字符在数组中的位置17. * 18. * param c 19. * return 20. */ 21. private static int getIndex(char c) 22. int p = -1; 23. for (int i = 0; i hexDigits.length; i+) 24. if (hexDigitsi = c) 25. p = i; 26. break; 27. 28. 29. return p; 30. 31. 32. /* 33. * 将字节转化成字符串,转换算法如下: 34. * 1:每个字节长度为 8 位, 分割为两个 4 位, 高四位和低四位 35. * 2:将每个四位换算成16 进制,并且对应 ascii码,如 0 x01 对应1,0 x0d 对应 d, 具体对应关系请见数组hexDigits 36. * 3:将得到的字符拼成字符串37. * 38. * param bytes 39. * return 40. */ 41. public static String byteToChar(byte bytes) 42. / 每个字节用 16 进制表示的话, 使用两个字符, 所以字符数组长度是字节数字长度的2 倍43. char str = new charbytes.length * 2; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 11 页,共 13 页 - - - - - - - - - 44. / 表示转换结果中对应的字符位置45. int = 0; 46. / 每一个字节转换成 16 进制字符47. for (int i = 0; i 为逻辑右移,右移后,高四位变成低四位,需要对低四位之外的值进行消零运算50. strk+ = hexDigitsbyte0 4 & 0 xf ; 51. / 取字节中低 4 位( 右边四位 )的数字转换,并且和0 xf进行 逻辑与 运算,以消除高位的值,得到纯净的低四位值52. strk+ = hexDigitsbyte0 & 0 xf ; 53. 54. return new String(str); 55. 56. 57. /* 58. * 将字节转换成二进制数组, 是 byteToChar 方法的逆运算, 转换算法如下 : 59. * 1:将字符按顺序每两个分为一组,分别找出每个字符在映射表hexDigits中的索引值,请见getIndex(char c)方法 60. * 2:每两个字符一组进行运算, 将第一个字符的索引值逻辑左移四位,并和 0 xf 进行 逻辑或 运算,目的是将低四位都设置为1,因为逻辑左移后,低四位都变成0 了 61. * 3:将第二个字符的索引值和62.0 xf0进行逻辑或 运算,目的的是将高位设置为1 63. * 4:将两个运算完的索引值进行 逻辑与 运算,得到了两个字符所代表的一个字节值 64. * 5:依次运算 , 最后得到字节数组 , 返回65. * 66. * param str 67. * return 68. */ 69. public static byte charToByte(String str) 70. char chars = str.toCharArray(); 71. byte bytes = new bytechars.length / 2; 72. int k = 0; 73. for (int i = 0; i chars.length; i = i + 2) 74. / 得到索引值75. byte high = (byte) getIndex(charsi); 76. byte low = (byte) getIndex(charsi + 1); 77. / 第一个字符索引逻辑左移四位, 并进行或运算 , 将低四位设置为 1 78. high = (byte) (high 4) | 0 xf ); 79. / 第二个字符索引进行或运算, 将高四位设置为 1 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 12 页,共 13 页 - - - - - - - - - 80. low = (byte) (low | 0 xf0 ); 81. / 两个字节进行与运算82. bytesk+ = (byte) (high & low); 83. 84. return bytes; 85. 86. 87. public static void main(String args) 88. String str = abgcd1234; 89. System.out.println(原始字符串 : + str); 90. String result = ByteUtil.byteToChar(str.getBytes(); 91. System.out.println(运算结果 : + result); 92. byte resultbytes = ByteUtil.charToByte(result); 93. System.out.println(逆运算结果: + new String(resultbytes); 94. 95. 来自 http:/ 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 13 页,共 13 页 - - - - - - - - -