详解NodeJs支付宝移动支付签名及验签


Posted in NodeJs onJanuary 06, 2017

非常感谢 :http://www.jianshu.com/p/8513e995ff3a?utm_campaign=hugo&utm_medium=reader_share&utm_content=note&utm_source=weibo 的文章,如果不是找到这篇文章我可能还要继续坑几天,代码也基本都是照着他的搬过来的,不过支付宝移动支付文档写的非常糟糕而且没有node的SDK和demo,写起来异常痛苦..好在找到了这篇文章顺便折腾了一下午支付宝的技术人员总算把移动支付整个流程给做完了,所以就顺便记录一下自己遇到的坑,和对移动支付整个流程的梳理。

详解NodeJs支付宝移动支付签名及验签

支付宝给的流程图还是很清晰的,其实基本流程就是

  1. 用户向服务器请求一个付款
  2. 服务器生成一个带签名的订单发送给客户端
  3. 客户端通过这个订单向app sdk请求付款
  4. sdk把用户引入支付宝付款界面进行支付
  5. 支付成功后支付宝向前端返回支付成功结果,并且向服务器发送一个支付通知
  6. 服务器接收通知并且验证是否是支付宝发送的成功结果

app客户端需要做的很简单:

  1. 向自己的服务器请求一个订单,
  2. 接收到订单后,向支付宝sdk发情一个支付请求
  3. 交易结束后返回一个成功或者失败

服务器做的事情稍微多一点(注意:服务端需要存放应用的私钥进行签名,还有支付宝的公钥进行验签):

1.接收到客户端请求时候,生成一个带签名订单返回给客户端,中间的步奏有

1) 把相应的配置数据生成一个数组,再把数组的数据生成一个有序的字符串

//将支付宝发来的数据生成有序数列
function getVerifyParams(params) {
 var sPara = [];
 if(!params) return null;
 for(var key in params) {
 if((!params[key]) || key == "sign" || key == "sign_type") {
 continue;
 };
 sPara.push([key, params[key]]);
 }
 sPara = sPara.sort();
 var prestr = '';
 for(var i2 = 0; i2 < sPara.length; i2++) {
 var obj = sPara[i2];
 if(i2 == sPara.length - 1) {
 prestr = prestr + obj[0] + '=' + obj[1] + '';
 } else {
 prestr = prestr + obj[0] + '=' + obj[1] + '&';
 }
 }
 return prestr;
}

  2) 将这组支付串进行RSA-SHA1算法,得到的结果再与存在服务端的私钥进行签名

//验签
function veriySign(params) {
 try {
 var publicPem = fs.readFileSync('./rsa_public_key.pem');
 var publicKey = publicPem.toString();
 var prestr = getVerifyParams(params);
 var sign = params['sign'] ? params['sign'] : "";
 var verify = crypto.createVerify('RSA-SHA1');
 verify.update(prestr);
 return verify.verify(publicKey, sign, 'base64')

 } catch(err) {
 console.log('veriSign err', err)
 }
}

  3) 有序的字符串+得到的签名+签名方法就是生成的订单,将这组订单返回给客户端

//发送订单号
 sendAlipay: function(req, res) {
 var code = ""
 for(var i = 0; i < 4; i++) {
 code += Math.floor(Math.random() * 10);
 }
 //订单号暂时由时间戳与四位随机码生成
 AlipayConfig.out_trade_no = Date.now().toString() + code;
 var myParam = getParams(AlipayConfig);
 var mySign = getSign(AlipayConfig)
 var last = myParam + '&sign="' + mySign + '"&sign_type="RSA"';
 console.log(last)
 return res.send(last)
 }

2.前半段的工作就做完了,接下来如果前端支付成功,支付宝会向我们预留好的回调接口发送一个POST请求,让我们验证用户是否支付成功

  1) 将支付宝发送过来的数据生成一个有序的字符串

//将支付宝发来的数据生成有序数列
function getVerifyParams(params) {
 var sPara = [];
 if(!params) return null;
 for(var key in params) {
 if((!params[key]) || key == "sign" || key == "sign_type") {
 continue;
 };
 sPara.push([key, params[key]]);
 }
 sPara = sPara.sort();
 var prestr = '';
 for(var i2 = 0; i2 < sPara.length; i2++) {
 var obj = sPara[i2];
 if(i2 == sPara.length - 1) {
 prestr = prestr + obj[0] + '=' + obj[1] + '';
 } else {
 prestr = prestr + obj[0] + '=' + obj[1] + '&';
 }
 }
 return prestr;
}

  2) 将获取的数据进行hash然后根据公钥进行对签名的有效应验证,返回true和false

//验签
function veriySign(params) {
 try {
 var publicPem = fs.readFileSync('./rsa_public_key.pem');
 var publicKey = publicPem.toString();
 var prestr = getVerifyParams(params);
 var sign = params['sign'] ? params['sign'] : "";
 var verify = crypto.createVerify('RSA-SHA1');
 verify.update(prestr);
 return verify.verify(publicKey, sign, 'base64')

 } catch(err) {
 console.log('veriSign err', err)
 }
}

  3) 如果验签成功再生成支付宝通知url,来验证是否是支付宝发来的通知(支付宝的验证一大堆,脑壳都痛了),如果有数据则说明确实是支付宝发来的通知,这次交易有效

//回调验签
 getAlipay: function(req, res) {
 console.log(req.body)
 var params = req.body
 var mysign = veriySign(params);
 //验证支付宝签名mysign为true表示签名正确
 console.log(mysign)
 try {
 //验签成功
 if(mysign) {
 if(params['notify_id']) {
 var partner = AlipayConfig.partner;
 //生成验证支付宝通知的url
 var url = 'https://mapi.alipay.com/gateway.do?service=notify_verify&' + 'partner=' + partner + '¬ify_id=' + params['notify_id'];
 console.log('url:' + url)
 //验证是否是支付宝发来的通知
 https.get(url, function(text) {
 //有数据表示是由支付宝发来的通知
 if(text) {
 //交易成功
 console.log('success')
 } else {
 //交易失败
 console.log('err')
 }
 })
 }
 }
 } catch(err) {
 console.log(err);
 }
 }

这样整个流程就跑完了,代码原博客都有,这里最多只是有些改成了sails的写法,主要写一下这次遇到的几个坑和值得注意的几个地方

1. 由于移动支付的文档描述不清楚,私钥其实上上传到账户信息的mapi网管产品密钥里:

详解NodeJs支付宝移动支付签名及验签

而不是上传到应用的密钥里

2. 移动支付只支持RSA(SHA1)

3.  ./是在sails里获取的到根目录下的密钥(有点搞不懂sails的这个路径)

4. 生成订单时候的有序字符串格式是body="测试" ,有双引号,但是验签生成的有序字符串里不能有双引号

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

NodeJs 相关文章推荐
PHPStorm 2020.1 调试 Nodejs的多种方法详解
Sep 17 NodeJs
NodeJS 模块开发及发布详解分享
Mar 07 NodeJs
Nodejs sublime text 3安装与配置
Jun 19 NodeJs
在NodeJS中启用ECMAScript 6小结(windos以及Linux)
Jul 15 NodeJs
浅析Nodejs npm常用命令
Jun 14 NodeJs
Nodejs回调加超时限制两种实现方法
Jun 09 NodeJs
Nodejs之TCP服务端与客户端聊天程序详解
Jul 07 NodeJs
Nodejs进阶之服务端字符编解码和乱码处理
Sep 04 NodeJs
NodeJs通过async/await处理异步的方法
Oct 09 NodeJs
nodejs 如何手动实现服务器
Aug 20 NodeJs
nodejs基础之buffer缓冲区用法分析
Dec 26 NodeJs
搭建一个nodejs脚手架的方法步骤
Jun 28 NodeJs
nodejs和php实现图片访问实时处理
Jan 05 #NodeJs
nodejs实例解析(输出hello world)
Jan 03 #NodeJs
Highcharts+NodeJS搭建数据可视化平台示例
Jan 01 #NodeJs
nodejs利用http模块实现银行卡所属银行查询和骚扰电话验证示例
Dec 30 #NodeJs
浅谈Nodejs中的作用域问题
Dec 26 #NodeJs
nodeJS删除文件方法示例
Dec 25 #NodeJs
详解nodejs 文本操作模块-fs模块(五)
Dec 23 #NodeJs
You might like
php中将数组存到文件里的实现代码
2012/01/19 PHP
php json_encode与json_decode详解及实例
2016/12/13 PHP
PHP实现mysqli批量执行多条语句的方法示例
2017/07/22 PHP
ASP中进行HTML数据及JS数据编码函数
2009/11/11 Javascript
Egret引擎开发指南之视觉编程
2014/09/03 Javascript
node.js中的buffer.slice方法使用说明
2014/12/10 Javascript
JS基于cookie实现来宾统计记录访客信息的方法
2015/08/04 Javascript
js实现的鼠标滚轮滚动切换页面效果(类似360默认页面滚动切换效果)
2016/01/27 Javascript
HTML的select控件美化
2017/03/27 Javascript
AngularJS中使用ngModal模态框实例
2017/05/27 Javascript
jquery对table做排序操作的实例演示
2017/08/10 jQuery
js实现鼠标跟随运动效果
2020/08/02 Javascript
babel之配置文件.babelrc入门详解
2018/02/22 Javascript
使用RxJS更优雅地进行定时请求详析
2019/06/02 Javascript
vue动态配置模板 'component is'代码
2019/07/04 Javascript
layui点击按钮页面会自动刷新的解决方案
2019/10/25 Javascript
JSONP解决JS跨域问题的实现
2020/05/25 Javascript
微信小程序实现天气预报功能(附源码)
2020/12/10 Javascript
[01:28:31]《加油DOTA》真人秀 第五期
2014/09/01 DOTA
[08:56]DOTA2-DPC中国联赛2月23日Recap集锦
2021/03/11 DOTA
python检测主机的连通性并记录到文件的实例
2018/06/21 Python
Python GUI编程 文本弹窗的实例
2019/06/11 Python
Django实现分页显示效果
2019/10/31 Python
python如何处理程序无法打开
2020/06/16 Python
记一次django内存异常排查及解决方法
2020/08/07 Python
Python爬虫破解登陆哔哩哔哩的方法
2020/11/17 Python
Python Http请求json解析库用法解析
2020/11/28 Python
CSS3 Columns分列式布局方法简介
2014/05/03 HTML / CSS
Html5元素及基本语法详解
2016/08/02 HTML / CSS
您的网上新华书店:文轩网
2016/08/24 全球购物
如何写毕业求职自荐信
2013/11/06 职场文书
国家励志奖学金个人先进事迹材料
2014/05/04 职场文书
改革共识倡议书
2014/08/29 职场文书
2014年电厂个人工作总结
2014/11/27 职场文书
优秀团员自我评价
2015/03/10 职场文书
老员工辞职信范文
2015/05/12 职场文书