银联支付的测试开发做的很完善,可以下载各个语言的测试包,进行开发测试,但是并没有 nodejs 的,难点就是证书签名还有验签这两个步骤。
其实银联加密方式和支付宝微信不同的地方在于,使用了非对称加密,意思是为了在网络中传输安全,双方约定各自产生一个公钥还有私钥,私钥自己保存,公钥公开给对方(你要发送信息的人都知道)。当需要传输秘密的信息时候,用自己的私钥加密,发给对方,对方收到信息后,为了判定这个是否伪造(是不是确实从你这儿发送给他的),那么拿出你的公钥进行验证,发现是一样的,那么就可以确定这个确实是你发送的。这样做就可以保证信息的安全。
下面是 code :
银联配置文件:config.js
//配置银联支付需要的数据 - 这都是银联测试商户信息,可以上 https://merchant.unionpay.com/portal/login.jsp 去申请测试商户 merId: '777290058136713', //商户id font_trans_url: 'https://101.231.204.80:5000/gateway/api/frontTransReq.do', //网关跳转至银联平台支付页面地址 sigle_query_url: 'https://101.231.204.80:5000/gateway/api/queryTrans.do', //单笔查询请求地址 sign_cert_dir: __dirname + '/certificates', //签名证书路径 certId: '40220995861346480087409489142384722381', sign_cert_pwd: '0000000', //签名证书密码 sign_cert_path: __dirname + '/certificates/700000000000001_acp.pfx', //签名用私钥证书 validate_cert_path: __dirname + '/certificates/verify_sign_acp.cer', //验签用银联公钥证书
.pfx 结尾的都是用密码加密过后的私钥
.cer 结尾的都是公钥
银联支付模块 unionPay.js
var validator = require('validator'), util = require('util'), _ = require('underscore'), crypto = require('crypto'), x509 = require('x509'), sha1 = require('sha1'), wopenssl = require('wopenssl'), config = require('./config'); //加载银联配置 //银联网关支付 var unionPay = { //创建预订单 /* * 参数 parms: {out_trade_no: OUT_TRADE_NO, fee: FEE} * out_trade_no 商户订单号 fee 订单金额,单位分 */ sdk_front_notice_url: 'http://'+ config.domain +'/unionPay/result', //银联网关支付前台通知地址 sdk_back_notic_url: 'http://'+ config.domain +'/unionPay/productPay', //银联网关支付后台通知地址 createOrder: function(parms, callback) { var errmsg; var timeStamp = parms.timeStamp; if(parms.payType==0) { var back_notic_url = 'http://'+ config.domain +'/unionPay/productPay'; } else if(parms.payType==1) { var back_notic_url = 'http://'+ config.domain +'/unionPay/rechargePay'; } else { var back_notic_url = this.sdk_back_notic_url; } var formData = { 'version' : '5.0.0', //版本号 'encoding' : 'utf-8', //编码方式 'txnType' : '01', //交易类型 'txnSubType' : '01', //交易子类 'bizType' : '000201', //业务类型 'frontUrl' : this.sdk_front_notice_url, //前台通知地址 'signMethod' : '01', //签名方法 'channelType' : '08', //渠道类型,07-PC,08-手机 'accessType' : '0', //接入类型 'currencyCode' : '156', //交易币种,境内商户固定156 //TODO 以下信息需要填写 'merId' : config.merId, //商户代码,请改自己的测试商户号,此处默认取demo演示页面传递的参数 'orderId' : parms.out_trade_no, //商户订单号,8-32位数字字母,不能含“-”或“_”,此处默认取demo演示页面传递的参数,可以自行定制规则 'txnTime' : timeStamp, //订单发送时间timestamp,格式为YYYYMMDDhhmmss,取北京时间,此处默认取demo演示页面传递的参数 'txnAmt' : parms.fee, //交易金额,单位分 'backUrl' : back_notic_url, //后台通知地址 'certId' : '' //可不必填写,在SignKeyFromPfx中返回 }; var privateKey; var certId; var cert; SignKeyFromPfx(function(err , result){ if (err) { errmsg = '证书签名失败'; } else { certId = result.certId; privateKey = result.key; formData.certId = certId; if (formData.signature) { delete formData.signature } //----签名开始---- //参数转变为签名串 var unionPay_parms = transForSign(formData); //摘要 var unionPay_parms_sha1 = sha1(unionPay_parms); //签名 var signer = crypto.createSign('RSA-SHA1'); signer.update(unionPay_parms_sha1); var signature_base64 = signer.sign(privateKey, 'base64'); //放入域中 formData.signature = signature_base64; //加入表单请求银联的地址 formData.action_url = config.font_trans_url; //console.log(formData); if (errmsg) { callback(errmsg); } else { callback(null,formData); } } }); }, //签名 sign: function(parms, callback) { var errmsg; var formData = parms; SignKeyFromPfx(function(err , result){ if (err) { errmsg = '证书签名失败'; } else { certId = result.certId; privateKey = result.key; if (formData.signature) { delete formData.signature } //----签名开始---- //参数转变为签名串 var unionPay_parms = transForSign(formData); //摘要 var unionPay_parms_sha1 = sha1(unionPay_parms); //签名 var signer = crypto.createSign('RSA-SHA1'); signer.update(unionPay_parms_sha1); var signature_base64 = signer.sign(privateKey, 'base64'); //放入域中 formData.signature = signature_base64; //console.log(formData); if (errmsg) { callback(errmsg); } else { callback(null,formData); } } }); }, //验签 validate: function(parms,callback) { var validate_signature = parms.signature; delete parms.signature; var formData = parms; ValidateKeyFromCer(formData,validate_signature,function(err , result){ if (err || !validate_signature || !formData) { console.log('验签失败'); callback('验签失败'); } else { var publicKey = result.key; if (formData.signature) { delete formData.signature } //----验签开始---- var unionPay_parms = transForSign(formData); var unionPay_parms_sha1 = sha1(unionPay_parms); //console.log('待验证签:' + validate_signature); var verifier = crypto.createVerify('RSA-SHA1'); //console.log('验证签名public key:\n' + publicKey); //console.log('验证签名src_sign:' + unionPay_parms_sha1); verifier.update(new Buffer(unionPay_parms_sha1, 'utf-8')); var is_success = verifier.verify(publicKey, validate_signature, 'base64'); if (is_success) { callback(null,formData); } else { console.log('验签不相等'); callback('验签不相等'); } } }); } }; // 签名串算法--将参数排序,转成键值对格式字符串 function transForSign(params){ var array = [] for (var i in params) { array.push('' + i + '=' + params[i]) } var stringSignTemp = _.sortBy(array, function (str) { return str; }); return stringSignTemp.join('&'); }; //通过证书密码获得证书的rsa-privatekey值和证书Id function SignKeyFromPfx(callback){ if (config.certsData) { callback(null, config.certsData); } else { var certPath = config.sign_cert_path; var certPwd = config.sign_cert_pwd; var certDir = config.sign_cert_dir; var p12 = wopenssl.pkcs12.extract(certPath, certPwd); //console.log(p12.certificate); //p12.certificate和p12.rsa var certs = wopenssl.x509.parseCert(p12.certificate); //因为不知道怎么将十六进制证书id:certs.serial变成十进制证书id,因为这是个很大的整形biglong var certsData = {}; certsData.certId = config.certId; certsData.key = p12.rsa; certsData.ca = certs; //存入config config.certsData = certsData; callback(null,certsData); //{key: String, certId: String, ca: Array} } }; //获得验签证书的rsa-publickey值 function ValidateKeyFromCer(formData, signature, callback){ if (config.validCertsData) { callback(null, config.validCertsData); } else { var validateCertPath = config.validate_cert_path; var certs = wopenssl.x509.parseCert(validateCertPath); //console.log(certs); var fs = require('fs'); var CERTIFICATE = fs.readFileSync(validateCertPath); console.log(CERTIFICATE); var publicKey = CERTIFICATE.toString('ascii'); var validCertsData = {}; validCertsData.key = publicKey; validCertsData.cert = CERTIFICATE; config.validCertsData = validCertsData; if (publicKey) { callback(null,validCertsData); } else { msg = '验签失败'; callback(msg); } } }; //转化时间格式函数 function format(){ //时间格式化 var format = 'yyyyMMddhhmmss'; date = new Date(); var o = { 'M+' : date.getMonth() + 1, //month 'd+' : date.getDate(), //day 'h+' : date.getHours(), //hour 'm+' : date.getMinutes(), //minute 's+' : date.getSeconds(), //second 'q+' : Math.floor((date.getMonth() + 3) / 3), //quarter 'S' : date.getMilliseconds() //millisecond }; if (/(y+)/.test(format)) format = format.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)); for (var k in o) if (new RegExp('(' + k + ')').test(format)) format = format.replace(RegExp.$1, RegExp.$1.length == 1 "_blank" href="https://101.231.204.80:5000">https://101.231.204.80:5000需要换为 https://gateway.95516.com ,生产环境中除非是从商户提交审核的域名发起的请求,否则一律会报错 亲爱的用户,您本次交易可能存在风险.以上所述是小编给大家介绍的NodeJS整合银联网关支付DEMO,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 中国武警男声合唱团《辉煌之声1天路》[DTS-WAV分轨]
- 紫薇《旧曲新韵》[320K/MP3][175.29MB]
- 紫薇《旧曲新韵》[FLAC/分轨][550.18MB]
- 周深《反深代词》[先听版][320K/MP3][72.71MB]
- 李佳薇.2024-会发光的【黑籁音乐】【FLAC分轨】
- 后弦.2012-很有爱【天浩盛世】【WAV+CUE】
- 林俊吉.2012-将你惜命命【美华】【WAV+CUE】
- 晓雅《分享》DTS-WAV
- 黑鸭子2008-飞歌[首版][WAV+CUE]
- 黄乙玲1989-水泼落地难收回[日本天龙版][WAV+CUE]
- 周深《反深代词》[先听版][FLAC/分轨][310.97MB]
- 姜育恒1984《什么时候·串起又散落》台湾复刻版[WAV+CUE][1G]
- 那英《如今》引进版[WAV+CUE][1G]
- 蔡幸娟.1991-真的让我爱你吗【飞碟】【WAV+CUE】
- 群星.2024-好团圆电视剧原声带【TME】【FLAC分轨】