微信支付小結

一.公衆平臺設置網頁授權域名

 

  • 方案一:

 

在做項目集成微信登錄以及微信支付的時候,都需要進行用戶授權。這個授權的流程可以簡單描述爲: 

1. 用戶從我們的應用觸發需要授權的操作,比如點擊微信登錄; 

 

2. 應用收到這種用戶請求後,將用戶重定向到微信提供的一個授權頁面: 

 

 

3. 用戶通過微信掃碼(PC端授權,上邊左圖)或者點擊確認按鈕(移動端授權,上邊右圖)告知微信,授權應用訪問自己的微信賬號信息; 
4. 微信收到用戶的授權許可後,生成授權碼,並把它作爲參數回調至應用的某個頁面; 
5. 應用的回調頁面在接收到微信的回調請求後,拿到其中的授權碼,並通過微信官方提供的access token api接口獲取access token; 
6. 最後通過access token以及微信官方提供的另一個userinfo api接口就能獲取到用戶的微信賬號信息。

爲了實現這個過程,首先要爲應用申請一個微信公衆號,並將應用最終部署的域名設置到微信公衆號設置裏面的授權回調頁面域名這個選項裏面。微信官方對這個選項的說明如下:

關於網頁授權回調域名的說明

1、在微信公衆號請求用戶網頁授權之前,開發者需要先到公衆平臺官網中的“開發 - 接口權限 - 網頁服務 - 網頁帳號 - 網頁授權獲取用戶基本信息”的配置選項中,修改授權回調域名。請注意,這裏填寫的是域名(是一個字符串),而不是URL,因此請勿加 http:// 等協議頭;

2、授權回調域名配置規範爲全域名,比如需要網頁授權的域名爲:www.qq.com,配置以後此域名下面的頁面http://www.qq.com/music.html 、 http://www.qq.com/login.html 都可以進行OAuth2.0鑑權。但http://pay.qq.com 、 http://music.qq.com 、 http://qq.com無法進行OAuth2.0鑑權

3、如果公衆號登錄授權給了第三方開發者來進行管理,則不必做任何設置,由第三方代替公衆號實現網頁授權即可

由此可見,這個規則極其嚴格。如果說我們的應用最終部署的時候只有一個域名,那麼這種規則不會有什麼問題;但是考慮到將來應用的複雜性,我們可能在應用設計之初就會對應用做拆分,然後不同的業務採用不同的二級域名來部署。比如一個帶有交易的應用,你可能會把登錄註冊,交易管理和常規業務都獨立出來,然後採用以下的方式來部署它們: 
www.your.com 部署常規業務; 
trade.your.com 部署交易管理的業務; 
passport.your.com 部署登錄註冊的業務; 
在這種模式下,如果集成微信登錄和微信支付,前面說的授權回調頁面域名的規則就會給應用帶來問題。在這裏:至少可以確認trade.your.com和passport.your.com都需要前面的介紹的用戶微信授權,但是它們是兩個不同的子域名,而且我們只有一個公衆號;根據授權回調頁面域名的原則,它只能用一個域名,並且只有回調地址的域名與該設置完全相同,才能成功發起微信授權,否則就會提示rediret_uri參數錯誤或者引發無法回調的問題。

那麼這種情況該如何處理?

當下的解決方案是引入一個新的非常簡單的應用來作爲微信授權的代理服務,可以這麼做: 
1. 把公衆號的網頁授權接口域名設置成另外一個子域名,如proxy.your.com; 
2. 然後把php_weixin_proxy裏面的index.php部署到proxy.your.com

php_weixin_proxy下的index.php是一個很簡單的php文件,你可以直接查看源碼瞭解它的實現方式。因爲當前項目的環境,我採用php來完成這個代理服務實現,實際上,你完全可以用任意平臺語言來完成類似的功能。

當其它業務需要發起微信授權時,將授權請求先發到proxy.your.com,然後proxy.your.com會把這個請求轉發到微信; 
當用戶同意授權後,proxy.your.com會收到微信的授權回調,並把回調結果(code、state參數)原封不動地再返回給最開始發起授權的業務。

唯一的區別在於,在不使用proxy.your.com的時候,你從應用發起微信授權的鏈接應該是這樣的: 
https://open.weixin.qq.com/connect/qrconnect?appid=xxxxx&redirect_uri=http%3A%2F%2Fpassport.your.com%2F&response_type=code&scope=snsapi_login&state=584bc87e11ff37492#wechat_redirect 
用了proxy.your.com之後,這個授權鏈接就應該是這樣的: 
http://proxy.your.com/?appid=xxxxx&redirect_uri=http%3A%2F%2Fpassport.your.com%2Flogin%2Fnotify&response_type=code&scope=snsapi_base&state=584bc87e11ff37492&device=pc

後面這個鏈接跟上面的比: 
1. 後面的鏈接中的host變成了proxy.your.com,也就是代理的授權回調域名; 
2. 後面的多了一個device參數,這個是必要的。因爲微信pc端跟移動端的授權地址是不一樣的,而後面的鏈接是發送個proxy.your.com的,所以需要多加個參數告訴它在轉發給授權申請給微信的時候,是用PC端還是移動端的授權地址。

整體方案思路

<?php
function is_HTTPS()
{
    if (!isset($_SERVER['HTTPS'])) return FALSE;
    if ($_SERVER['HTTPS'] === 1) {  //Apache
        return TRUE;
    } elseif ($_SERVER['HTTPS'] === 'on') { //IIS
        return TRUE;
    } elseif ($_SERVER['SERVER_PORT'] == 443) { //其他
        return TRUE;
    }
    return FALSE;
}
function getDomain()
{
    $server_name = $_SERVER['SERVER_NAME'];
    if (strpos($server_name, 'www.') !== false) {
        return substr($server_name, 4);
    }
    return $server_name;
}
$appid = '';
$scope = 'snsapi_login';
$state = '';
$code = '';
$redirect_uri = '';
$device = '';
$protocol = '';
if (is_HTTPS()) {
    $protocol = 'https';
} else {
    $protocol = 'http';
}
if (isset($_GET['device'])) {
    $device = $_GET['device'];
}
if (isset($_GET['appid'])) {
    $appid = $_GET['appid'];
}
if (isset($_GET['state'])) {
    $state = $_GET['state'];
}
if (isset($_GET['redirect_uri'])) {
    $redirect_uri = $_GET['redirect_uri'];
}
if (isset($_GET['code'])) {
    $code = $_GET['code'];
}
if (isset($_GET['scope'])) {
    $scope = $_GET['scope'];
}
if ($code == 'test') {
    exit;
}
if (empty($code)) {
    $authUrl = '';
    if ($device == 'pc') {
        $authUrl = 'https://open.weixin.qq.com/connect/qrconnect';
    } else {
        $authUrl = 'https://open.weixin.qq.com/connect/oauth2/authorize';
    }
    $options = [
        $authUrl,
        '?appid=' . $appid,
        '&redirect_uri=' . urlencode($protocol . '://' . $_SERVER['HTTP_HOST'] . '/'),
        '&response_type=code',
        '&scope=' . $scope,
        '&state=' . $state,
        '#wechat_redirect'
    ];
    //把redirect_uri先寫到cookie
    header(implode('', [
        "Set-Cookie: redirect_uri=",
        urlencode($redirect_uri),
        "; path=/; domain=",
        getDomain(),
        "; expires=" . gmstrftime("%A, %d-%b-%Y %H:%M:%S GMT", time() + 60),
        "; Max-Age=" + 60,
        "; httponly"
    ]));
    header('Location: ' . implode('', $options));
} else {
    if (isset($_COOKIE['redirect_uri'])) {
        $back_url = urldecode($_COOKIE['redirect_uri']);
        header('Location: ' . implode('', [
                $back_url,
                strpos($back_url, '?') ? '&' : '?',
                'code=' . $code,
                '&state=' . $state
            ]));
    }
}
?>

 

 

 

  • 方案二、

在授權域名下部署一個get-weixin-code.html

 

二、商戶平臺設置公衆號支付的授權目錄

JSAPI發起支付請求的url必須在授權目錄之下

下單前需要先調用【網頁授權獲取用戶信息】接口獲取到用戶的Openid,這裏就會用到第一步設置的中轉方法

三、商戶平臺設置掃碼支付的支付消息回調通知

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