已解决了,就是sessionkey来回传递的问题,传了code就好了;sessionkey来回传递可能被编码转义了,能存服务端还是存服务端吧
-----------------------
问题描述
在使用 wx.requestVirtualPayment 进行虚拟支付时,持续报错 SIGNATURE_INVALID errCode: -15005,即使服务端返回的signature经验证完全正确。
复现步骤
- 用户打开小程序
- 调用支付接口,使用
parse.getSessionKey()获取有效的sessionKey(通过wx.checkSession()验证) - 将sessionKey传递给服务端
/activity/payment/virtualPay - 服务端使用HMAC-SHA256算法计算signature
- 调用
wx.requestVirtualPayment并传入服务端返回的参数 - 报错:
requestVirtualPayment:fail SIGNATURE_INVALID errCode: -15005
预期结果
支付正常进行
实际结果
报错 SIGNATURE_INVALID errCode: -15005
关键信息
服务端请求参数
{
"serviceKey": "userdownloadtraffic",
"tradeType": 1,
"userId": "1405204833103639620",
"count": 5,
"sessionKey": "vSIhSBBIIsz5tjP0hqFxZQ==",
"equipment": "ios",
"platform": "miniprogram"
}
服务端返回数据
{
"code": "200",
"message": "操作成功",
"data": {
"signData": {
"offerId": "1450493965",
"buyQuantity": 994,
"env": 1,
"currencyType": "CNY",
"outTradeNo": "Fotoo202604012039292964878004225",
"attach": "fotoo"
},
"signDataStr": "{\"offerId\":\"1450493965\",\"buyQuantity\":994,\"env\":1,\"currencyType\":\"CNY\",\"outTradeNo\":\"Fotoo202604012039292964878004225\",\"attach\":\"fotoo\"}",
"paySig": "83cb3ac3fb66592fa9e44580336b46c6523adea31896ba3968538545878f5f2b",
"signature": "344c448f7f41f716cdb502fcd8781e3d5158faaad8aabe20becb80fd698b6d3a",
"mode": "short_series_coin"
}
}
签名验证结果
使用Python验证服务端signature计算完全正确:
import hmac
import hashlib
import json
sessionKey = 'vSIhSBBIIsz5tjP0hqFxZQ=='
signData = {
'offerId': '1450493965',
'buyQuantity': 994,
'env': 1,
'currencyType': 'CNY',
'outTradeNo': 'Fotoo202604012039292964878004225',
'attach': 'fotoo'
}
signDataStr = json.dumps(signData, separators=(',', ':'))
signature = hmac.new(
sessionKey.encode('utf-8'),
signDataStr.encode('utf-8'),
hashlib.sha256
).hexdigest()
# 计算结果: 344c448f7f41f716cdb502fcd8781e3d5158faaad8aabe20becb80fd698b6d3a
# 服务端返回: 344c448f7f41f716cdb502fcd8781e3d5158faaad8aabe20becb80fd698b6d3a
# 匹配结果: True
前端代码逻辑
sessionKey获取逻辑
// utils/parse.js
getSessionKey(hasFouce=false){
return new Promise(async (success,fail)=>{
if(!hasFouce){
this.sessionKey=await this.checkSessionKey();
if(this.sessionKey){return success(this.sessionKey);}
}
wx.login({
success:async res=>{
App.demand('/sys/loadSessionKey','GET',{jsCode:res.code}).then(res=>{
this.sessionKey=res.data;
getApp().setStorageSync('sessionKey',this.sessionKey);
success(this.sessionKey)
})
},
})
})
},
checkSessionKey(){
return new Promise((success,fail)=>{
this.sessionKey=getApp().getStorageSync('sessionKey');
if(!this.sessionKey) return success('');
wx.checkSession({
success:res=>{
return success(this.sessionKey)
},
fail:res=>{
return success('')
}
})
})
}
虚拟支付调用逻辑
// pages/wxpay/wxpay.js
async requestIAPPayment() {
let payParams=(await App.demand('/activity/payment/virtualPay','POST',{
serviceKey:this.options.serviceKey,
tradeType:1,
userId:this.options.userId,
count:this.options.count||1,
sessionKey:await parse.getSessionKey(),
equipment: this.getEquipment(),
platform: "miniprogram",
})).data;
wx.requestVirtualPayment({
signData: payParams.signDataStr,
paySig: payParams.paySig,
signature: payParams.signature,
mode: payParams.mode,
success:(res)=> {
console.info('requestVirtualPayment success', res)
},
fail: (res)=> {
console.error('requestVirtualPayment fail',res);
},
});
}
问题分析
- 服务端签名验证通过:使用服务端返回的sessionKey和signDataStr,通过HMAC-SHA256算法计算出的signature与服务端返回值完全一致
- sessionKey获取逻辑正常:
- 使用
wx.checkSession()验证sessionKey有效性 - 验证通过则复用缓存的sessionKey
- 验证失败才调用
wx.login()重新获取
- 错误持续出现:即使使用相同的有效sessionKey,错误仍然持续
- 可能原因推测:
- 微信客户端内部维护的sessionKey状态与前端通过
wx.login()获取的不一致 wx.checkSession()返回成功,但微信客户端内部sessionKey实际上已经失效- iOS平台的特殊行为或bug
补充信息
- 环境变量:
env=1(沙箱环境) - 多次测试使用相同sessionKey:
vSIhSBBIIsz5tjP0hqFxZQ== - 每次都复用缓存的sessionKey,没有频繁调用
wx.login()

简单点直接wx.login获取code给服务端,服务端用code换sessionKey减少传来传去的问题
wx.checkSession()是用来校验最后一次获取 code 对应的登录态是否还有效,并不能代表你当前存在本地的sessionKey 是有效的,校验sessionKey 是需要服务端来校验
“签名算得对”,但目前你不能证明“签名用的 sessionKey 是有效的”
支付前不要复用缓存 sessionKey,直接强制重新获取,验证一下就知道是不是旧 sessionKey 问题了
补充信息
sessionKey 无论强制刷新还是使用缓存的,都是一样的错误
------------------
已解决了,就是sessionkey的问题,传了code就好了;sessionkey来回传递可能被编码转义了,能存服务端还是存服务端吧