V2版接口和V3版接口规则差异说明:
- 参数格式:V2接口为XML,V3接口为JSON
- 签名方式:V2接口为MD5或HMAC-SHA256,V3接口为非对称密钥SHA256-RSA
- 回调加密:V2接口无需加密,V3接口为AES-256-GCM加密
本文章主要协助开发者定位JSAPI调起支付返回签名验证失败报错的问题,大家可根据以下步骤逐步排查。
V2版本排查步骤:
步骤一、签名类型与下单时的签名类型不一致
检查调起支付的签名类型是否与下单一致,比如下单是HMAC-SHA256,而调起支付用的是MD5
步骤二、生成签名原串的参数和实际请求参数不一致
检查生成签名串的参数与实际发起请求的参数是否一致,例如生成签名时的时间戳、随机串与实际发起请求的不一致
步骤三、调起支付时的大小写不正确
检查客户端调用时的传参是否正确,注意参数是否区分大小写,参数大小写不正确将会导致签名错误
步骤四、使用的API版本不一致
检查下单和调起支付时使用的API版本是否一致,比如下单用的V2版本的API,而调起支付又参考的是V3的API来实现。
步骤五、使用的商户号信息不一致
检查下单和调起支付时使用的商户号是否一致,比如下单用的是A商户号,而调起支付又使用的是B商户号的信息生成签名
步骤六、使用的key不正确
需要用APIv2密钥生成签名, key设置路径:微信商户平台(pay.weixin.qq.com)-->账户中心-->账户设置-->API安全-->设置API密钥
步骤七、没有重新生成签名
调起支付的签名需要重新按照调起支付文档中规定的参数和要求生成,而不能直接使用统一下单接口的签名值(sign)
V3版本排查步骤:
步骤一、生成签名原串的参数和实际请求参数不一致
检查生成签名串的参数值与客户端实际发起请求的参数值是否一致
步骤二、调起支付时构造签名串的字段和格式不正确
检查调起支付时构造签名串格式是否正确,参与签名字段及格式应是:
步骤三、调起支付时的大小写不正确
检查客户端调用时的传参是否正确
步骤四、使用的API版本不一致
检查下单和调起支付时使用的API版本是否一致,比如调起支付参考的V3的API规则实现,而下单用的V2统一下单。
步骤五、使用的商户号信息不一致
检查下单和调起支付时使用的商户号是否一致,比如下单用的是A商户号,而调起支付又使用的是B商户号的信息生成签名
步骤六、没有重新生成sign
调起支付的签名(paySign)需要重新按照调起支付文档中规定的参数和要求生成,而不能直接使用下单接口的签名值(signature)
如通过以上步骤仍然无法解决你的问题,可以在帖子提供关键信息(比如签名工具中的截图和通过postman请求报错)并留言,记得对敏感信息打码,比如key,mch_id,appid等
附录:
1、SDK与相关API规则介绍
- 微信支付API v3 SDK介绍
- 验签工具使用指引
- 微信支付官方提供的排查签名步骤介绍
- JSAPI调起支付版本文档(V3普通商户版本)
- JSAPI调起支付版本文档(V2普通商户版本)
- JSAPI调起支付版本文档(V3服务商版本)
- JSAPI调起支付版本文档(V2服务商版本)
我是v3,我的原因是小程序发起支付的签名也用了后端支付接口的签名了,原来微信小程序发起支付填写的签名还需要另外生成,大家注意这个点。
您好 微信支付V3调用JSAPi支付 使用官方验签工具提示这个错误 查看明文格式,大小写,密钥格式都验证无误。还是提示这个问题,期待回复
下单成功,返回 prepay_id 正常。小程序用JSAPI调起支付时扫码,返回“验证签名失败”。使用签名验收工具,在本地验证签名,是验证通过的。 微信只返回"requestPayment:fail cancel",一头雾水>_<。。。"request
PrivateKey privateKey = wechatPayConfig.getPrivateKey(wechatPayConfig.getKeyPemPath()); // 实例化签名对象 Signature signature = Signature.getInstance("SHA256withRSA"); signature.initSign(privateKey); signature.update(signStr.getBytes("utf-8")); // 生成签名 byte[] signed = signature.sign(); // 将签名转换为Base64编码的字符串 String sign = Base64.getEncoder().encodeToString(signed);
Payment:fail cancel"
生成和调用的值完全一样: timeStamp前-----1692074529 randoNumber前-----808804b5d1ee4b3695ffb2a2a78d3be9 timeStamp后-----1692074529 nonceStr后-----808804b5d1ee4b3695ffb2a2a78d3be9 后端获取sign代码: String sign(byte[] message) throws Exception { WxPayConfig config = wxPayService.getConfig(); //签名方式 Signature sign = Signature.getInstance("SHA256withRSA"); //私钥,通过MyPrivateKey来获取,这是个静态类可以接调用方法 ,需要的是_key.pem文件的绝对路径配上文件名 sign.initSign(config.getPrivateKey()); sign.update(message); System.out.println("sign-----------"+sign.sign()); return Base64.getEncoder().encodeToString(sign.sign()); } String buildMessage(String appId, String timeStamp,String nonceStr,String prepay_id) { System.out.println("timeStamp后-----"+timeStamp); System.out.println("nonceStr后-----"+nonceStr); return appId + "\n" + timeStamp + "\n" + nonceStr + "\n" + prepay_id + "\n"; } 前端调用的大小写也对: appId: data.appId, //公众号ID,由商户传入 timeStamp: data.timeStamp, //时间戳,自1970年以来的秒数 nonceStr: data.nonceStr, //随机串 package: data.package, signType: data.signType, //微信签名方式: paySign: data.paySign, //微信签名 还是报下面这个错是为什么???
invalid signature签名错误。建议按如下顺序检查:
确认签名算法正确,可用http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign 页面工具进行校验。
确认config中nonceStr(js中驼峰标准大写S), timestamp与用以签名中的对应noncestr, timestamp一致。
确认url是页面完整的url(请在当前页面alert(location.href.split('#')[0])确认),包括'http(s)://'部分,以及'?'后面的GET参数部分,但不包括'#'hash后面的部分。
确认 config 中的 appid 与用来获取 jsapi_ticket 的 appid 一致。
确保一定缓存access_token和jsapi_ticket。
确保你获取用来签名的url是动态获取的,动态页面可参见实例代码中php的实现方式。如果是html的静态页面在前端通过ajax将url传到后台签名,前端需要用js获取当前页面除去'#'hash部分的链接(可用location.href.split('#')[0]获取,而且需要encodeURIComponent),因为页面一旦分享,微信客户端会在你的链接末尾加入其它参数,如果不是动态获取当前链接,将导致分享后的页面签名失败。
更加具体的可参考文档:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html