獲取到 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);
使用服務端提供的數據發起支付請求即可。