Closed titop closed 3 years ago
欢迎pr
WechatPayMiddleware.php文件,第107~124行
return $handler($request, $options)->then( function (ResponseInterface $response) use ($request) { $code = $response->getStatusCode(); if ($code >= 200 && $code < 300) { if (!$response->getBody()->isSeekable() && \class_exists("\\GuzzleHttp\\Psr7\\CachingStream")) { $response = $response->withBody(new \GuzzleHttp\Psr7\CachingStream($response->getBody())); } if (!$this->validator->validate($response)) { if (\class_exists('\\GuzzleHttp\\Exception\\ServerException')) { throw new \GuzzleHttp\Exception\ServerException( "应答的微信支付签名验证失败", $request, $response); } else { throw new \RuntimeException("应答的微信支付签名验证失败", $code); } } } return $response; } );
接口返回的是json格式时,第114行会对返回数据进行合法性检验。
但是在 调用下载账单API 使用https://api.mch.weixin.qq.com/v3/billdownload/file?token=xxx 请求,返回的不是json,而是文本字符串,第114行没有对这种情况进行判断,导致抛出 "应答的微信支付签名验证失败"异常。
改成这样,可能适应性会更好一些。
if (strtolower($request->getHeader('Accept')[0]) === 'application/json' && !$this->validator->validate($response)) { if (\class_exists('\\GuzzleHttp\\Exception\\ServerException')) { throw new \GuzzleHttp\Exception\ServerException( "应答的微信支付签名验证失败", $request, $response); } else { throw new \RuntimeException("应答的微信支付签名验证失败", $code); } }
如果下载,返回的不是json格式字符串,在header中不传
[ 'Accept' => 'application/json' ]
或将 Accept设置为/,接口就能正常返回数据。
这个bug怎么没有反馈呢,我也遇到了,还没解决呢……
建议先使用空的validator来发请求
use WechatPay\GuzzleMiddleware\Validator;
class NoopValidator implements Validator
{
public function validate(\Psr\Http\Message\ResponseInterface $response)
{
return true;
}
}
$wechatpayMiddleware = WechatPayMiddleware::builder()
->withMerchant($merchantId, $merchantSerialNumber, $merchantPrivateKey)
->withValidator(new NoopValidator) // NOTE: 设置一个空的应答签名验证器,**不要**用在业务请求
->build();
建议这块处理逻辑这么弄:
hash_type
及 hash_value
构建一个Validator
,对返回内容验签
download_url
上,query
参数可能存有 tartype
字典,验签
逻辑要兼顾download_url
只有30秒有效时间,可选验签
逻辑加入有效性校验(这可能需要官方body JSON增加返回字段明示)这个bug怎么没有反馈呢,我也遇到了,还没解决呢……
补充说明下,这一点并不是bug而不修复。应答签名是保证应答报文的真实性、完整性和抗抵赖的关键信息,我们不希望增加类似判断content-type
不等于application/json
就不验签的“后门”。
我们的建议是调用方主动在账单文件下载接口使用NoopValidator
,只对这一个接口不验签。未来可能会在sdk中去提供具体的api供开发者直接使用。
@TheNorthMemory 的建议更好,该接口适用的Validator应使用上一步获取的账单摘要对获得的账单进行完整性校验。
建议这块处理逻辑这么弄:
- 依赖上文返回的
hash_type
及hash_value
构建一个Validator
,对返回内容验签
download_url
上,query
参数可能存有tartype
字典,验签
逻辑要兼顾download_url
只有30秒有效时间,可选验签
逻辑加入有效性校验(这可能需要官方body JSON增加返回字段明示)
在微信的开发平台上已经获取了您的解决办法,再次感谢!
WechatPayMiddleware.php文件,第107~124行
接口返回的是json格式时,第114行会对返回数据进行合法性检验。
但是在 调用下载账单API 使用https://api.mch.weixin.qq.com/v3/billdownload/file?token=xxx 请求,返回的不是json,而是文本字符串,第114行没有对这种情况进行判断,导致抛出 "应答的微信支付签名验证失败"异常。
改成这样,可能适应性会更好一些。
如果下载,返回的不是json格式字符串,在header中不传
或将 Accept设置为/,接口就能正常返回数据。