共计 3282 个字符,预计需要花费 9 分钟才能阅读完成。
获取到 prepay_id 后将参数再次签名传输给 APP 发起支付。
相信有不少同学因为看到统一下单返回的结果中有 sign 字段,会直接将结果返回给 APP 端,结果 APP 端没办法调起微支付。其实需要对 APP 端用到的字段数据按“统一下单的签名方式”签名后得到的 sign,才是 APP 端需要的 sign。
微信支付 App 支付 在服务端调用统一下单接口后,服务端需要将返回的订单数据进行二次签名后才能返回给 App 端。开发文档中说的并不是很明确,因为统一下单的返回数据和二签的原数据上存在一些重叠。
微信支付服务端 sdk 提供了 WxPayResults 类,类中也的确提供了生成签名方法,即对结果集签名,源码如下:
以 PHP 版为例,其他语言自行对照。
class WxPayResults extends WxPayDataBase
{
/**
* 生成签名 – 重写该方法
* @param WxPayConfigInterface $config 配置对象
* @param bool $needSignType 是否需要补 signtype
* @return 签名,本函数不覆盖 sign 成员变量,如要设置签名需要调用 SetSign 方法赋值
*/
public function MakeSign($config, $needSignType = false)
{
// 签名步骤一:按字典序排序参数
ksort($this->values);
$string = $this->ToUrlParams();
// 签名步骤二:在 string 后加入 KEY
$string = $string . “&key=” . $config->GetKey();
// 签名步骤三:MD5 加密或者 HMAC-SHA256
if (strlen($this->GetSign()) <= 32) {
// 如果签名小于等于 32 个, 则使用 md5 验证
$string = md5($string);
} else {
// 是用 sha256 校验
$string = hash_hmac(“sha256”, $string, $config->GetKey());
}
// 签名步骤四:所有字符转为大写
$result = strtoupper($string);
return $result;
}
}
注意步骤三,是需要获取 sign 来判断使用什么方式生成 sign 的,是不是有种鸡生蛋,蛋生鸡的短路既视感。在 APP 端调起支付的参数列表的 sign 参数里有提示“注意:签名方式一定要与统一下单接口使用的一致”,所以这里的逻辑是要你将统一下单返回的 sign 传递进来,以便于统一签名方式。签名后一定要用真的签名去覆盖用来传递签名方式的“签名”。
在统一下单接口中,生成签名的流程是 $obj->setSign() 调用 $obj->makeSign(),而后我们可以 $obj->getSign() 将签名加到请求数据中。但在结果集类中,makeSign 却直接调用了 getSign 来判断使用何种方式生成签名,所以对结果集签名时,需确保结果集中包含了同一下单返回的 sign 字段数据,这样结果集才能满足“注意:签名方式一定要与统一下单接口使用的一致”的要求。
所以这个类对签名进行了重写的目的,主要是为了保证二次签名的签名方式与统一下订单的签名方式一致,将统一下单的签名作为 sign 传递给 WxPayResults 然后调用 makeSign,makeSign 就能判断出统一下单的签名方式,与之保持一致。
统一下单成功接口返回的数据
$uniorder = array (
‘appid’ => ‘wxd930ea5d5a258f4f’,//appid
‘device_info’ => ‘WEB’,
‘mch_id’ => ‘1900000109’,// 商户 id
‘nonce_str’ => ‘g6OZoULWyliPmiPm’,
‘prepay_id’ => ‘wx12143635206473d0a53e80f14278847815’,
‘result_code’ => ‘SUCCESS’,
‘return_code’ => ‘SUCCESS’,
‘return_msg’ => ‘OK’,
‘sign’ => ‘E91035CA24EDF115374BD2B4C4F9B419’,// 统一下单的签名
‘trade_type’ => ‘APP’,
)
服务端需要二签的数据
文档地址:https://pay.weixin.qq.com/wik…
package 暂填写固定值 Sign=WXPay
noncestr 并不一定要统一下单返回的 nonce_str,自己生成 32 位 的也可以
timestamp 自己生成即可
sign 传递统一下单返回的签名,以使得结果集签名和统一下单签名方式一致(或者你清楚的知道你对结果集签名的方式同下单的一致)
如果自己写,二不用 sdk 的话,我们需要对
<?php
// 传递的数据
$app_result = array (
‘appid’ => $uniorder[‘appid’],// 从统一下单的结果中取
‘partnerid’ => $uniorder[‘mch_id’],// 从统一下单的结果中取
‘prepayid’ => $uniorder[‘prepay_id’],// 从统一下单的结果中取
‘package’ => ‘Sign=WXPay’,// 自己写
‘noncestr’ => WxPayApi::getNonceStr();,// 自己写
‘timestamp ‘ => time(),// 自己写
);
// 与统一下单的签名方式一致即可
$sign = signMethodConsistWithUniOrder($app_result);
$app_result[‘sign’] = $sign;
// 返回给 APP 端
return $$app_result;
如果用 sdk 的务必要将 统一下单返回的数据里的签名 sign 也传递给 WxPayResults 类,已使得保证签名方式一致
<?php
// 传递的数据
// 传递的数据
$app_result = array (
‘appid’ => $uniorder[‘appid’],// 从统一下单的结果中取
‘partnerid’ => $uniorder[‘mch_id’],// 从统一下单的结果中取
‘prepayid’ => $uniorder[‘prepay_id’],// 从统一下单的结果中取
‘sign’ => $uniorder[‘sign’],// 用来使结果集签名方式与统一下单签名方式一致
‘package’ => ‘Sign=WXPay’,// 自己写
‘noncestr’ => WxPayApi::getNonceStr();,// 自己写
‘timestamp ‘ => time(),// 自己写
);
$wxPayResults = new WxPayResults();
// 构建 WxPayResults 对象
$wxPayResults->FromArray($app_result);
// 真正的返回数据的签名 覆盖用来统一签名方式的“签名”
$app_result[‘sign’] = $wxPayResults->makeSign($wxPayConfig);// 然后更新成二签后的 sign
// 返回给 APP 端
return $$app_result;
App 端调用微信支付的方式为
IWXAPI api;
PayReq request = new PayReq();
request.appId = “wxd930ea5d5a258f4f”;
request.partnerId = “1900000109”;
request.prepayId= “1101000000140415649af9fc314aa427”,;
request.packageValue = “Sign=WXPay”;
request.nonceStr= “1101000000140429eb40476f8896f4c9”;
request.timeStamp= “1398746574”;
request.sign= “7FFECB600D7157C5AA49810D2D8F28BC2811827B”;
api.sendReq(request);
使用服务端提供的数据发起支付请求即可。