wechatpay-apiv3/wechatpay-php

支付回调验签失败

Closed this issue · 6 comments

tashuo commented

运行环境

- OS: CentOS 7.9.2009
- PHP: 7.4.5
- Laravel: 8.12
- wechatpay-php: 1.4.8

描述你的问题现象

  1. 依照文档示例中"回调通知"章节写了一个支付回调的接口
  2. $inBody = file_get_contents('php://input') body使用的这个方式获取
  3. 现在验签$verifiedStatus一直通过不了,试着将相关的资源配置及请求数据打印出来,未看到明显的异常,请问该如何调试?
tashuo commented

但是后面的aes可以正常解密,是不是微信支付证书不匹配的问题

wechatpay-php/README.md

Lines 372 to 412 in fbe8d7c

```php
use WeChatPay\Crypto\Rsa;
use WeChatPay\Crypto\AesGcm;
use WeChatPay\Formatter;
$inWechatpaySignature = '';// 请根据实际情况获取
$inWechatpayTimestamp = '';// 请根据实际情况获取
$inWechatpaySerial = '';// 请根据实际情况获取
$inWechatpayNonce = '';// 请根据实际情况获取
$inBody = '';// 请根据实际情况获取,例如: file_get_contents('php://input');
$apiv3Key = '';// 在商户平台上设置的APIv3密钥
// 根据通知的平台证书序列号,查询本地平台证书文件,
// 假定为 `/path/to/wechatpay/inWechatpaySerial.pem`
$platformPublicKeyInstance = Rsa::from('file:///path/to/wechatpay/inWechatpaySerial.pem', Rsa::KEY_TYPE_PUBLIC);
// 检查通知时间偏移量,允许5分钟之内的偏移
$timeOffsetStatus = 300 >= abs(Formatter::timestamp() - (int)$inWechatpayTimestamp);
$verifiedStatus = Rsa::verify(
// 构造验签名串
Formatter::joinedByLineFeed($inWechatpayTimestamp, $inWechatpayNonce, $inBody),
$inWechatpaySignature,
$platformPublicKeyInstance
);
if ($timeOffsetStatus && $verifiedStatus) {
// 转换通知的JSON文本消息为PHP Array数组
$inBodyArray = (array)json_decode($inBody, true);
// 使用PHP7的数据解构语法,从Array中解构并赋值变量
['resource' => [
'ciphertext' => $ciphertext,
'nonce' => $nonce,
'associated_data' => $aad
]] = $inBodyArray;
// 加密文本消息解密
$inBodyResource = AesGcm::decrypt($ciphertext, $apiv3Key, $nonce, $aad);
// 把解密后的文本转换为PHP Array数组
$inBodyResourceArray = (array)json_decode($inBodyResource, true);
// print_r($inBodyResourceArray);// 打印解密后的结果
}
```

验签需要从头上取Wechatpay-Serial,其就是平台证书序列号,需要加载先行下载的平台证书并加载验签名。请试着理解这段样本代码先。

tashuo commented

wechatpay-php/README.md

Lines 372 to 412 in fbe8d7c

```php
use WeChatPay\Crypto\Rsa;
use WeChatPay\Crypto\AesGcm;
use WeChatPay\Formatter;
$inWechatpaySignature = '';// 请根据实际情况获取
$inWechatpayTimestamp = '';// 请根据实际情况获取
$inWechatpaySerial = '';// 请根据实际情况获取
$inWechatpayNonce = '';// 请根据实际情况获取
$inBody = '';// 请根据实际情况获取,例如: file_get_contents('php://input');
$apiv3Key = '';// 在商户平台上设置的APIv3密钥
// 根据通知的平台证书序列号,查询本地平台证书文件,
// 假定为 `/path/to/wechatpay/inWechatpaySerial.pem`
$platformPublicKeyInstance = Rsa::from('file:///path/to/wechatpay/inWechatpaySerial.pem', Rsa::KEY_TYPE_PUBLIC);
// 检查通知时间偏移量,允许5分钟之内的偏移
$timeOffsetStatus = 300 >= abs(Formatter::timestamp() - (int)$inWechatpayTimestamp);
$verifiedStatus = Rsa::verify(
// 构造验签名串
Formatter::joinedByLineFeed($inWechatpayTimestamp, $inWechatpayNonce, $inBody),
$inWechatpaySignature,
$platformPublicKeyInstance
);
if ($timeOffsetStatus && $verifiedStatus) {
// 转换通知的JSON文本消息为PHP Array数组
$inBodyArray = (array)json_decode($inBody, true);
// 使用PHP7的数据解构语法,从Array中解构并赋值变量
['resource' => [
'ciphertext' => $ciphertext,
'nonce' => $nonce,
'associated_data' => $aad
]] = $inBodyArray;
// 加密文本消息解密
$inBodyResource = AesGcm::decrypt($ciphertext, $apiv3Key, $nonce, $aad);
// 把解密后的文本转换为PHP Array数组
$inBodyResourceArray = (array)json_decode($inBodyResource, true);
// print_r($inBodyResourceArray);// 打印解密后的结果
}
```

验签需要从头上取Wechatpay-Serial,其就是平台证书序列号,需要加载先行下载的平台证书并加载验签名。请试着理解这段样本代码先。

这个逻辑有处理的,目前的平台证书用的固定一个(同下单逻辑),回调请求中的Wechatpay-Serial跟固定使用的那个平台证书序号也一致

tashuo commented

暂时去掉了验签逻辑,因为回调数据解密后还会请求查询订单接口验证状态,所以暂时影响也不大

暂时去掉了验签逻辑,因为回调数据解密后还会请求查询订单接口验证状态,所以暂时影响也不大

程序代码都已经为你甄别出来了问题,有问题就去解决掉;回避问题抑或延后处理都不是严谨的处事方式,尤其在支付领域。

Good luck dude.