Node.js关于微信支付V3版相关处理方法
Posted 袁代码
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Node.js关于微信支付V3版相关处理方法相关的知识,希望对你有一定的参考价值。
今天给大家写一个关于Node.js接入微信支付V3接口时一些毕竟复杂的点,主要就是请求签名Authorization、调起支付签名、回调参数解密等。
请求签名Authorization
在微信支付V3接口中,商户需要使用自身的私钥对API URL、消息体等关键数据的组合进行SHA-256 with RSA签名。请求的签名信息通过HTTP头Authorization传递,具体说明可以去看签名生成指南。没有携带签名或者签名验证不通过的请求,都不会被执行,并返回401 Unauthorized 。
那么如何生成这个Authorization呢,这个请求头,最麻烦的地方就是如何去生成
signature,其中我们使用jsrsasign模块来进行SHA256 with RSA加密,可以查看如下代码:
const KJUR, hextob64 = require('jsrsasign')
rsaSign(content, privateKey, hash='SHA256withRSA')
const signature = new KJUR.crypto.Signature(
alg: hash,
prvkeypem: privateKey
)
signature.updateString(content)
const signData = signature.sign()
// 将内容转成base64
return hextob64(signData)
//调用这个函数
let signature = this.rsaSign(`$method\\n$pathname\\n$timestamp\\n$onece_str\\n$bodyParamsStr\\n`,this.private_key,'SHA256withRSA')
//获取到signature后就可以获取到Authorization了
let Authorization = `WECHATPAY2-SHA256-RSA2048 mchid="$mchid",nonce_str="$onece_str",timestamp="$timestamp",signature="$signature",serial_no="$serial_no"`
其中mchid:商户号,onece_str:随机字符,timestamp:时间戳,serial_no:商户API证书序列号。这样在请求时在请求头里加入就可以了,如下:
headers:
'Content-Type':'application/json',
'Accept':'application/json',
'Authorization':Authorization
调起支付签名
通过上述请求后可以得到预支付交易会话标识prepay_id,然后我们需要再次进行签名,用于调起微信支付,代码如下:
paysign(options)
let timeStamp = this.createTimeStamp(), //时间戳
nonceStr = this.randomString(), //32位随机数
Ppackage = `prepay_id=$options`, //prepay_id
signType = 'RSA'; //加签方式
let PpaySign = `$this.appId\\n$timeStamp\\n$nonceStr\\n$Ppackage\\n`; //需要加签的字段拼接
let cryptStr = this.rsaSign(PpaySign, this.privateKey, 'SHA256withRSA'); //生成签名
let paySign = cryptStr;
return
timeStamp,
nonceStr,
package: Ppackage,
signType,
paySign
;
这里的rsaSign()函数就是上文提到的加密函数,只是这里的content参数有所不同而已,这样我们就可以直接调用起微信支付了。
回调参数解密
微信支付的回调都是需要验证解密之后才可以得到订单数据的,所以解密也是比较复杂的地方,这里我们使用crypto模块,对参数进行解密,代码如下:
const crypto = require("crypto");
decode(params)
const AUTH_KEY_LENGTH = 16;
// ciphertext = 密文,associated_data = 填充内容, nonce = 位移
const ciphertext, associated_data, nonce = params;
// 密钥
const key_bytes = Buffer.from(this.apiv3_private_key, 'utf8');
// 位移
const nonce_bytes = Buffer.from(nonce, 'utf8');
// 填充内容
const associated_data_bytes = Buffer.from(associated_data, 'utf8');
// 密文Buffer
const ciphertext_bytes = Buffer.from(ciphertext, 'base64');
// 计算减去16位长度
const cipherdata_length = ciphertext_bytes.length - AUTH_KEY_LENGTH;
// upodata
const cipherdata_bytes = ciphertext_bytes.slice(0, cipherdata_length);
// tag
const auth_tag_bytes = ciphertext_bytes.slice(cipherdata_length, ciphertext_bytes.length);
const decipher = crypto.createDecipheriv(
'aes-256-gcm', key_bytes, nonce_bytes
);
decipher.setAuthTag(auth_tag_bytes);
decipher.setAAD(Buffer.from(associated_data_bytes));
const output = Buffer.concat([
decipher.update(cipherdata_bytes),
decipher.final(),
]);
return output;
其中就是params回调返回值里的resource参数,这样就可以得到回调返回的信息了。
关于小程序 接入 支付宝支付 微信支付
有做过H5的支付 最近在做小程序的支付相关 就趁机来整理一波叭
首先在这里我们使用的是onemipay
先在composer下载如下类包
然后 我们接下来 写微信支付 支付宝支付相关,可以把这些方法封装一下。我们先讲接入微信支付
1:首先具当前小程序的对应的 APP_ID,SECRET,MCH_ID,API_KEY,记得登录商家后台 添加回对应的 授权回调目录
这里先构造支付网关,项目里的H5支付,小程序支付,APP,支付都可以根据此来延伸开。这里目前只有支付宝支付 微信支付两种方式
2:注意 小程序支付使用的是WechatPay_Js支付方式,在这里设置好 app_id ,mch_id _api_key等信息,对啦 再次还有一个微信回调地址 不要忘记设置哦
3:接下来就是支付宝支付,构造对应网关,设置相关信息,因为是在小程序中进行支付宝支付,不能直接跳转到支付宝,所以在这里是生成相应支付链接,到支付宝进行支付。此有一点是 ,由于项目中链接过长(请求参数/用户标识token) ,可进行一次短连接转化,这一部分可放在前端处理,也可以放在后端进行处理,根据项目实际情况来定。
支付接口贴代码
/** * 支付 * @param Request $request */ public function pay(Request $request) if (!$request->has('order_id')) return new TheParameterIsEmpty(); $au_id = $request->get('au_id'); $orderId = $request->input('order_id'); $payGenre = $request->input('pay_gateway'); $WeChat_type = $request->input('WeChat_type', 2);//默认 JSAPI $return_url = $request->input('return_url', ''); $order = ActivityOrder::getActivityOrder($orderId, $au_id); if (!$order instanceof ActivityOrder) return response_json(11029, config('code.11029')); $ActivityMarketing = ActivityMarket::getActByAmId($order->am_id); if (!$ActivityMarketing instanceof ActivityMarket) return response_json(11010, config('code.11010')); if ($ActivityMarketing->join_stint != 0 && $ActivityMarketing->join_stint <= $ActivityMarketing->join_stint_num) return response_json(11011, config('code.11011')); ActivityOrderRepository::setPayGenre($order, $payGenre); $gateway = PayGateFactory::getPayGate($payGenre); try return $this->getPayParameter($order, $gateway, $return_url ,$WeChat_type); catch (Exception $exception) Log::error($exception); return response_json(500, '服务器错误'); /** * @param ActivityOrder $order * @param GatewayInterface $gateway * @param $return_url //支付宝网页支付成功跳转地址 * @param $WeChat_type 2:JSAPI 3:H5 * @return \\Illuminate\\Http\\JsonResponse */ protected function getPayParameter(ActivityOrder $order, GatewayInterface $gateway, $return_url, $WeChat_type) $pay_type = $gateway instanceof AliPay ? 'AliPay' : 'WeChatPay'; $parameter = 1; if ($pay_type == 'AliPay') $parameter = 2;//支付宝网页支付 elseif ($pay_type == 'WeChatPay') $parameter = $WeChat_type; $gateway->getGateway($parameter); $gateway->setNotifyUrl('shop-ay/ny'); if ($pay_type == 'AliPay') $gateway->setReturnUrl($return_url); $gateway->setGatewayOrder($order); // if ($pay_type == 'WeChatPay') $gateway->setTimeExpire(date('yymdHms', time()+300)); $data = $gateway->response(); return response_json($data);
最后如果成功的话 请求返回应该是
注意:前端在对应调微信支付时 字段顺序要后对应后端加密的顺序一致哦 不然会出问题的
好啦 就到此为止啦
以上是关于Node.js关于微信支付V3版相关处理方法的主要内容,如果未能解决你的问题,请参考以下文章