微信公衆號開發中的支付流程

今天聊一下微信公衆號開發在授權網頁中的支付流程。

微型公衆號開發有以下幾個步驟:
1.獲取全局access_token
2.獲取網頁授權的access_token和refresh_token
3.獲取網頁授權的簽名(前端用於獲取調用JSSDK的權限)
4.公衆號支付-調用統一下單接口獲取prepay_id
5.公衆號支付-將簽名返回給前端用於請求微信公衆號支付

其中步驟1、2根據微信開發文檔很容易完成;第3步就開始用到簽名了,這一步的簽名相對來說比較好做;第4、5步微信支付中的簽名對第一次做微信支付開發的小夥伴來說就有點麻煩了。

下面從第3步開始說吧。

第3步:獲取網頁授權的簽名,前端調用JSSDK時,需要使用這個簽名。
這一步驟中,我們需要給前端返回如下數據(除jsApiList):
):

wx.config({
    debug: true, // 開啓調試模式,調用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數,可以在pc端打開,參數信息會通過log打出,僅在pc端時纔會打印。
    appId: '', // 必填,公衆號的唯一標識
    timestamp: , // 必填,生成簽名的時間戳
    nonceStr: '', // 必填,生成簽名的隨機串
    signature: '',// 必填,簽名
    jsApiList: [] // 必填,需要使用的JS接口列表
});

其中,signature是一個關鍵的參數。生成簽名的規則可以去這裏 https://mp.weixin.qq.com/wiki... 的 附錄1-JS-SDK使用權限簽名算法 中查看
生成簽名的代碼如下:

def post(self, request):
        url = request.data["url"]
        logger.debug("url:%s", url)
        # 權限驗證配置信息
        platform_info = {"appId": WXConfig.APPID, "timestamp": 0, "nonceStr": '', "signature": ''}

        # 時間戳
        timestamp = int(time.time())
        # 隨機字符串,改方法自己實現即可
        noncestr = ToolToken.generate_noncestr()
        # jsapi_ticket
        ticket = cache.get("jsapi_ticket")
        if not ticket:
            # 重新獲取jsapi_ticket
            wx = WXToken()
            # 此處根據說明文檔獲取jsapi_ticket即可
            wx.get_jsapi_ticket()

        logger.debug("ticket:%s", ticket)
        # 組合字符串,其中url是需要前端傳給我們的
        info_string = "jsapi_ticket=" + ticket + "&noncestr=" + noncestr + "&timestamp=" + str(timestamp) + "&url=" + url

        signature = hashlib.sha1(info_string.encode("utf-8")).hexdigest()
        platform_info["signature"] = signature
        platform_info["timestamp"] = timestamp
        platform_info["nonceStr"] = noncestr
        return Response(platform_info, status=status.HTTP_200_OK)

第4步:從這一步就開始調用微信支付的相關接口了。這裏一定要注意,調用微信支付接口時,一定要看最新的說明文檔,不要看舊的,不然會出現錯誤,並且不容易找到原因。
調用統一下單接口的代碼如下:

async def unify_order(self):
        """
        請求微信統一下單接口
        :return:
        """
        url = "https://api.mch.weixin.qq.com/pay/unifiedorder"
        headers = {'Content-Type': 'application/xml'}
        async with ClientSession() as session:
            async with session.post(url=url, data=self.xml_data, headers=headers) as res:
                ret = await res.text()
                logger.debug("ret:%s", ret)
                self.unify_order_data = self.xml_to_dict(ret)
                logger.debug("self.unify_order_data:%s", self.unify_order_data)

其中,self.xml_data內容如下:

<xml>
    <appid>你的appid</appid>
    <attach>pay</attach>
    <body>paytest</body>
    <mch_id>商戶號</mch_id>
    <detail>apple</detail>
    <nonce_str>你生成的隨機字符串</nonce_str>
    <notify_url>通知地址</notify_url>
    <openid>你的openid</openid>
    <out_trade_no>訂單號</out_trade_no>
    <spbill_create_ip>外網可訪問ip地址</spbill_create_ip>
    <total_fee>訂單金額</total_fee>
    <trade_type>JSAPI</trade_type>
    <sign_type>MD5</sign_type>
    <sign>簽名</sign>
</xml>

其中最後一個參數sign的值是需要通過其他參數加密得到的,簽名生成規則可以參考微信官方文檔。這裏需要說明一下,一定要加上sign_type這個參數(雖然官網說明文檔中把這個參數標記爲不是必須的),顯式指定加密方法,不然可能得到簽名錯誤的結果。

上面xml中的參數可以根據需求添加。

請求成功後,會返回prepay_id這個值,在下一步中會用到。返回結果可能如下:

{'return_code': 'SUCCESS', 'return_msg': 'OK', 'appid': appid, 'mch_id': 商戶號, 'nonce_str': 隨機字符串, 'sign': 簽名, 'result_code': 'SUCCESS', 'prepay_id': prepay_id, 'trade_type': 'JSAPI'}

第5步:這一步中需要將以下信息返回個前端:

wx.chooseWXPay({
    timestamp: 0, // 支付簽名時間戳,注意微信jssdk中的所有使用timestamp字段均爲小寫。但最新版的支付後臺生成簽名使用的timeStamp字段名需大寫其中的S字符
    nonceStr: '', // 支付簽名隨機串,不長於 32 位
    package: '', // 統一支付接口返回的prepay_id參數值,提交格式如:prepay_id=\*\*\*)
    signType: '', // 簽名方式,默認爲'SHA1',使用新版支付需傳入'MD5'
    paySign: '', // 支付簽名
    success: function (res) {
        // 支付成功後的回調函數
            }
        });

除了success,其他參數都需要返回給前端。從 timestamp到paySign這幾個參數中,最難處理的又是簽名paySign。當你看到上面那段js代碼時,可能你看到的文檔已經過時了,有可能誤導你。生成簽名給前端時可能只使用了timestamp,nonceStr,package,signType這幾個參數,但是你將這樣生成的名返回前端時,前端請求後可能得到簽名認證錯誤的提示。

正確的簽名生成方式是timestamp,nonceStr,package,signType和key(微信商戶平臺配置的key)都需要參與簽名;並且package的值不是第4步中返回的prepay_id的值,而是”prepay_id=”+prepay_id這樣一個字符串。具體如下:

appId=${appid}&nonceStr=${nonceStr}&package=prepay_id=${prepay_id}&signType=MD5&timeStamp=${timeStamp}&key=${key}

將上面的字符串加密即可獲得paySign的值。
前端獲得簽名後,再請求微信服務器,下面的支付流程就可以繼續下去了。

以上如有錯誤之處,歡迎交流指正!

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