微信支付之APIv3
1.安装依赖包
仓库地址:https://github.com/TheNorthMemory/wechatpay-axios-plugin
安装命令:npm install wechatpay-axios-plugin
2.生成v3平台证书
wxpay crt -m 1602388066 -s 53F5D1A7289C36ACCBB359DD591E52A5408FCB3C -f F:/zhangjia/projectWXAPIv3/static/pem/wx/apiclient_key.pem -k pppppppppppppppppppppppp -o F:/zhangjia/projectWXAPIv3/static/pem/wx
· 参数解释
wxpay crt -m {商户号} -s {商户证书序列号} -f {商户API私钥文件路径} -k {APIv3密钥(32字节)} -o {生成证书保存地址}
· 参数完整解释
wxpay crt
The WeChatPay APIv3's Certificate Downloader
cert
-m, --mchid The merchant's ID, aka mchid. [string] [required]
-s, --serialno The serial number of the merchant's certificate aka serialno. [string] [required]
-f, --privatekey The path of the merchant's private key certificate aka privatekey. [string] [required]
-k, --key The secret key string of the merchant's APIv3 aka key. [string] [required]
-o, --output Path to output the downloaded WeChatPay's platform certificate(s) [string] [default: "/tmp"]
Options:
--version Show version number [boolean]
--help Show help [boolean]
-u, --baseURL The baseURL [string] [default: "https://api.mch.weixin.qq.com/"]
3.初始化
· 引用导入包
const { Wechatpay } = require('wechatpay-axios-plugin');
const { readFileSync } = require('fs');
· 初始化各项参数
// 商户号
const merchantId = '1602388066';
// 商户证书序列号
// 也可以使用openssl命令行获取证书序列号
// openssl x509 -in /path/to/merchant/apiclient_cert.pem -noout -serial | awk -F= '{print $2}'
const merchantCertificateSerial = '53F5D1A7289C36ACCBB359DD591E52A5408FCB3C';// API证书不重置,商户证书序列号就是个常量
// 商户私钥,文件路径假定为 `/path/to/merchant/apiclient_key.pem`
const merchantPrivateKeyFilePath = './static/pem/wx/apiclient_key.pem';
// 商户API私钥 PEM格式的文本字符串或者文件buffer
const merchantPrivateKeyInstance = readFileSync(merchantPrivateKeyFilePath);
// 第2小节中生成的平台证书,可由下载器 `wxpay crt -m {商户号} -s {商户证书序列号} -f {商户API私钥文件路径} -k {APIv3密钥(32字节)} -o {保存地址}`
// 载器生成并假定保存为 `./static/pem/wx/wechatpay_61164AFB43674E6C3C4D3C09EFB175596CBE2EA8.pem`
const platformCertificateFilePath = './static/pem/wx/wechatpay_61164AFB43674E6C3C4D3C09EFB175596CBE2EA8.pem';
const platformCertificateInstance = readFileSync(platformCertificateFilePath);
// 平台证书序列号,下载器下载后有提示序列号字段,也可由命令行查询:
// openssl x509 -in ./static/pem/wx/wechatpay_61164AFB43674E6C3C4D3C09EFB175596CBE2EA8.pem -noout -serial | awk -F= '{print $2}'
const platformCertificateSerial = '61164AFB43674E6C3C4D3C09EFB175596CBE2EA8';
const wxpay = new Wechatpay({
mchid: merchantId,
serial: merchantCertificateSerial,
privateKey: merchantPrivateKeyInstance,
certs: {[platformCertificateSerial]: platformCertificateInstance,},
// 使用APIv2时,需要至少设置 `secret`字段,示例代码未开启
// APIv2密钥(32字节)
// secret: 'your_merchant_secret_key_string',
// // 接口不要求证书情形,例如仅收款merchant对象参数可选
// merchant: {
// cert: readFileSync('/path/to/merchant/apiclient_cert.pem'),
// key: merchantPrivateKeyInstance,
// // or
// // passphrase: 'your_merchant_id',
// // pfx: fs.readFileSync('/your/merchant/cert/apiclient_cert.p12'),
// },
});
4.前端页面JSAPI调起支付API
· 调起方法 WeixinJSBridge.invoke (只在微信浏览器内起作用)
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId": data.appId, //公众号名称,由商户传入
"timeStamp": data.timeStamp, //时间戳,自1970年以来的秒数
"nonceStr": data.nonceStr, //随机串
"package": data.package,//"prepay_id=up_wx2120185573033"
"signType": data.signType, //微信签名方式
"paySign": data.paySign//微信签名
},
function (res) {
if (res.err_msg == "get_brand_wcpay_request:ok") {
// 使用以上方式判断前端返回,微信团队郑重提示:
//res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
}
});
注意:
· 以上字段均通过post后端接口得到,如后续小节的 unifiedorderAPIV3 下单接口;
· 以上字段均通过post后端接口得到,如后续小节的 unifiedorderAPIV3 下单接口;
· 其中 微信签名 需要加密算法单独计算。
5.APIv3数据签名(后台下单接口返回数据时使用)
· 引入依赖包
const {Rsa, Formatter} = require('wechatpay-axios-plugin')
const privateKey = require('fs').readFileSync('/your/merchant/priviate_key.pem')
· 数据签名加密算法
const params = {
appId: config.app_id,//应用ID
timeStamp: `${Formatter.timestamp()}`,//时间戳
nonceStr: Formatter.nonce(),//随机字符串,32位数
package: 'prepay_id='+res.data.prepay_id,//订单详情扩展字符串,prepay_id=wx1111
signType: 'RSA',
}
params.paySign = Rsa.sign(Formatter.joinedByLineFeed(
params.appId, params.timeStamp, params.nonceStr, params.package
), privateKey)
console.info(params)
6.后台下单接口方法详细内容(JSAPI)v3
· JSAPI合单支付下单
wxpay.v3.combineTransactions.jsapi
.post({/*文档参数放这里就好*/})
.then(res => console.info(res.data))
.catch(({response: {status, statusText, data}}) => console.error(status, statusText, data))
· JSAPI下单举例,此处将APIv3数据签名方法付诸实践,并将结果返回给前端调起支付页面
详细参数含义见微信开发文档 :
https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml
https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml
app.post('/unifiedorderAPIV3', function (req, response) {
const openid = req.body.openid;
// 商户订单号
const out_trade_no = 'test' + new Date().getTime();
// 统一下单的相关参数
wxpay.v3.pay.transactions.jsapi
.post({
mchid: config.mch_id,
out_trade_no: out_trade_no,
appid: config.app_id,
description: '测试jsapi支付功能',
notify_url: 'https://weixin.qq.com/',
amount: {
total: 1,
currency: 'CNY'
},
payer: {
openid: openid
}
})
.then(res => {
// APIv3数据签名
const params = {
appId: config.app_id,
timeStamp: `${Formatter.timestamp()}`,
nonceStr: Formatter.nonce(),
package: 'prepay_id='+res.data.prepay_id,
signType: 'RSA',
}
params.paySign = Rsa.sign(Formatter.joinedByLineFeed(
params.appId, params.timeStamp, params.nonceStr, params.package
), privateKey)
//console.info(params)
response.send(params);// APIv3数据签名后返回给前端
// response.send(res.data);
})
.catch(({response: {status, statusText, data}}) => console.log(status, statusText, data))
});
7.notify_url 对应后台方法
· 微信支付后,支付结果通知会以 post 方式发送到 notify_url 对应地址,如 notify_url 的具体地址为 xxxx/wxresponse 时候:
//微信支付后回调地址
app.post('/wxresponse', function (req, res) {
console.log(req.body);
let key = `zhangjia123456789123456789123456`;
let nonce = req.body.resource.nonce; // 加密使用的随机串
let associated_data = req.body.resource.associated_data; // 加密用的附加数据
let ciphertext = req.body.resource.ciphertext; // 加密体 base64
let payData = weixin_PAY.V3decodeByAES(undefined, ciphertext, nonce, associated_data);//第一个参数有默认值
console.log(payData);
// 订单状态更新操作
res.send({
"code": "SUCCESS",
"message": "成功"
});
});
·微信支付结果通知数据格式见【微信官方文档】
·其中加密数据解密方法具体为:
/**
* 解密微信支付或退款通知数据数据
* 使用AEAD_AES_256_GCM解密数据
* @param cipherText 密文
* @param key API V3密钥
* @param nonce nonce字符串
* @param add associated_data字符串
*/
function V3decodeByAES(key = config.mch_V3_key, ciphertext, nonce, associated_data) {
// 解密 ciphertext字符 AEAD_AES_256_GCM算法
ciphertext = Buffer.from(ciphertext, 'base64');
let authTag = ciphertext.slice(ciphertext.length - 16);
let data = ciphertext.slice(0, ciphertext.length - 16);
let decipher = crypto.createDecipheriv('aes-256-gcm', key, nonce);
decipher.setAuthTag(authTag);
decipher.setAAD(Buffer.from(associated_data));
let decoded = decipher.update(data, null, 'utf8');
decipher.final();
let payData = JSON.parse(decoded); //解密后的数据
return payData;
}
参考:https://github.com/TheNorthMemory/wechatpay-axios-plugin
赞 (0)