獲取到 prepay_id 後將參數再次簽名傳輸給 APP 發起支付

獲取到 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...

clipboard.png

  • 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);

使用服務端提供的數據發起支付請求即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章