收藏
回答

微信小程序虚拟支付 SIGNATURE_INVALID (-15005) 错误?


已解决了,就是sessionkey来回传递的问题,传了code就好了;sessionkey来回传递可能被编码转义了,能存服务端还是存服务端吧

-----------------------


问题描述

在使用 wx.requestVirtualPayment 进行虚拟支付时,持续报错 SIGNATURE_INVALID errCode: -15005,即使服务端返回的signature经验证完全正确。

复现步骤

  1. 用户打开小程序
  2. 调用支付接口,使用 parse.getSessionKey() 获取有效的sessionKey(通过 wx.checkSession() 验证)
  3. 将sessionKey传递给服务端 /activity/payment/virtualPay
  4. 服务端使用HMAC-SHA256算法计算signature
  5. 调用 wx.requestVirtualPayment 并传入服务端返回的参数
  6. 报错: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);
      },
    });
}

问题分析

  1. 服务端签名验证通过:使用服务端返回的sessionKey和signDataStr,通过HMAC-SHA256算法计算出的signature与服务端返回值完全一致
  2. sessionKey获取逻辑正常:
  • 使用 wx.checkSession() 验证sessionKey有效性
  • 验证通过则复用缓存的sessionKey
  • 验证失败才调用 wx.login() 重新获取
  1. 错误持续出现:即使使用相同的有效sessionKey,错误仍然持续
  2. 可能原因推测:
  • 微信客户端内部维护的sessionKey状态与前端通过 wx.login() 获取的不一致
  • wx.checkSession() 返回成功,但微信客户端内部sessionKey实际上已经失效
  • iOS平台的特殊行为或bug

补充信息

  • 环境变量:env=1(沙箱环境)
  • 多次测试使用相同sessionKey:vSIhSBBIIsz5tjP0hqFxZQ==
  • 每次都复用缓存的sessionKey,没有频繁调用 wx.login()


最后一次编辑于  04-02
回答关注问题邀请回答
收藏

4 个回答

  • 神经蛙
    神经蛙
    04-01

    简单点直接wx.login获取code给服务端,服务端用code换sessionKey减少传来传去的问题

    04-01
    有用 1
    回复 6
    • vking
      vking
      04-01
      parse.getSessionKey(true) 可以强制每次支付前获取新的sessionKey,依然报签名错误;传code感觉不解决问题啊,和强制获取sessionKey一样吧?难道sessionKey传送被转码/编码了,但我们之前其它地方(解析电话、群信息。。。)也是这样传,功能都正常
      04-01
      回复
    • 神经蛙
      神经蛙
      04-01回复vking
      百分百是传递出问题了吧(sessionKey中有=,来回编码可能有问题)。你paySign没问题,就只能是sessionKey的问题,这也是建议你直接用code的原因。
      04-01
      回复
    • 神经蛙
      神经蛙
      04-01
      另外,sessionKey这种属于敏感数据,不应该直接存储的客户端的。
      04-01
      回复
    • Memory (私信不回复)
      Memory (私信不回复)
      04-01回复神经蛙
      这还传递个鬼哦,sessionkey存前端真的人才
      04-01
      1
      回复
    • vking
      vking
      04-02回复神经蛙
      好的,尝试下,我也看到=号了,历史遗留问题,就一直在前端
      04-02
      回复
    查看更多(1)
  • Memory (私信不回复)
    Memory (私信不回复)
    04-01

    wx.checkSession()是用来校验最后一次获取 code 对应的登录态是否还有效,并不能代表你当前存在本地的sessionKey 是有效的,校验sessionKey 是需要服务端来校验

    “签名算得对”,但目前你不能证明“签名用的 sessionKey 是有效的”

    支付前不要复用缓存 sessionKey,直接强制重新获取,验证一下就知道是不是旧 sessionKey 问题了

    04-01
    有用
    回复 4
    • vking
      vking
      04-01
      parse.getSessionKey(true) 可以强制每次支付前获取新的sessionKey,依然报签名错误;由于有问题,我才将代码调整为使用缓存sessionKey;传code感觉不解决问题啊,和强制获取sessionKey一样吧?
      04-01
      回复
    • Memory (私信不回复)
      Memory (私信不回复)
      04-01回复vking
      一个应该在服务端维护的东西,你为什么非要扔前端去处理呢?
      04-01
      回复
    • vking
      vking
      04-02回复Memory (私信不回复)
      历史遗迹,项目小时候服务端用不到,就扔给前端了;尝试下不传了,让服务端存
      04-02
      回复
    • vking
      vking
      04-02
      已解决了,就是sessionkey的问题,传了code就好了,谢谢
      04-02
      回复
  • vking
    vking
    04-01

    补充信息

    sessionKey 无论强制刷新还是使用缓存的,都是一样的错误

    ------------------

    已解决了,就是sessionkey的问题,传了code就好了;sessionkey来回传递可能被编码转义了,能存服务端还是存服务端吧


    04-01
    有用
    回复
  • 智能回答 智能回答 本次回答由AI生成
    04-01
    有用
登录 后发表内容