1. 程式人生 > >微信掃一掃登入網站

微信掃一掃登入網站

微信網站掃一掃登入

標籤(空格分隔): wechat

上手須知

要想使用微信掃一掃就可以登入網站,首先要有微信開發平臺賬號,並且通過開發者資質認證(認證需要通過稽核,稽核費300人民幣),然後新增網頁應用準備網站資訊登記表等資訊提價稽核,有公眾號的可以繫結公眾號,最終你會得到 appid 和 appsecret 然後就可以愉快的玩耍了

科普微信授權原理

Created with Raphaël 2.1.2微信使用者微信使用者第三方應用第三方應用微信開發平臺微信開發平臺第三方應用第三方應用微信開發平臺微信開發平臺請求登入第三方應用請求oauth2授權請求使用者確認使用者確認拉起第三方應用或重定向到第三方的伺服器,並帶上code
通過code加上appid appsecret獲取access_token返回使用者相關資訊

前端的開啟方式

前端有兩種開啟方式

  • 通過重定向到微信的頁面然後使用者掃描二維碼授權,再重定向回第三方網站
  • 通過js直接顯示二維碼登入,不用跳轉微信頁面

第一種方式是通過後臺重定向過去的所以前端只需要寫個連結就行了,第二種方式是在頁面上直接顯示二維碼登入減少了跳頁面的時間,這種方式需要在網頁上用js實現,一般第二種用的比較多

使用js顯示微信掃一掃二維碼的開啟方式

步驟1:在頁面中先引入如下JS檔案(支援https):

https://res.wx.qq.com
/connect/zh_CN/htmledition/js/wxLogin.js

步驟2:在需要使用微信登入的地方例項以下JS物件:

var obj = new WxLogin({
     id:"login_container", // 需要顯示的容器id
     appid: "",  // 公眾號appid wx*******
     scope: "snsapi_login",  // 網頁預設即可
     redirect_uri: "", // 授權成功後回撥的url
     state: "", // 可設定為簡單的隨機數加session用來校驗
     style: "black", // 提供"black"、"white"可選。二維碼的樣式
href: "" // 外部css檔案url,需要https });

引數說明

引數 是否必須 說明
self_redirect true:手機點選確認登入後可以在 iframe 內跳轉到 redirect_uri,false:手機點選確認登入後可以在 top window 跳轉到 redirect_uri。預設為 false。
id 第三方頁面顯示二維碼的容器id
appid 應用唯一標識,在微信開放平臺提交應用稽核通過後獲得
scope 應用授權作用域,擁有多個作用域用逗號(,)分隔,網頁應用目前僅填寫snsapi_login即可
redirect_uri 重定向地址,需要進行UrlEncode
state 用於保持請求和回撥的狀態,授權請求後原樣帶回給第三方。該引數可用於防止csrf攻擊(跨站請求偽造攻擊),建議第三方帶上該引數,可設定為簡單的隨機數加session進行校驗
style 提供”black”、”white”可選,預設為黑色文字描述
href 自定義樣式連結,第三方可根據實際需求覆蓋預設樣式

使用者點選確認授權後網頁會自動跳轉redirect_uri

前端掃碼分析

!
function(a, b, c) {
    function d(a) {
        var c = "default";
        a.self_redirect === !0 ? c = "true": a.self_redirect === !1 && (c = "false");
        var d = b.createElement("iframe"),
        e = "https://open.weixin.qq.com/connect/qrconnect?appid=" + a.appid + "&scope=" + a.scope + "&redirect_uri=" + a.redirect_uri + "&state=" + a.state + "&login_type=jssdk&self_redirect=" + c;
        e += a.style ? "&style=" + a.style: "",
        e += a.href ? "&href=" + a.href: "",
        d.src = e,
        d.frameBorder = "0",
        d.allowTransparency = "true",
        d.scrolling = "no",
        d.width = "300px",
        d.height = "400px";
        var f = b.getElementById(a.id);
        f.innerHTML = "",
        f.appendChild(d)
    }
    a.WxLogin = d
} (window, document);

上段程式碼主要功能是根據使用者配置的訊息在頁面上嵌入一個iframe,我們看到的二維碼是iframe和請掃描等提示語都是iframe中的

這裡先給大家一個連結看看 點我
開啟iframe的連結返回的是一個網頁,再開啟遊覽器的開發者工具可以看到一個長連線請求

https://long.open.weixin.qq.com/connect/l/qrconnect?uuid=081ciRVWnFkIOwL8&_=1534297144336

這個請求帶有兩個引數一個是 uuid 還有一個 是 _ 看樣子應該是時間戳,這個請求在沒掃描之前一直是阻塞的,如果27秒沒有掃碼會自動斷開連線,並且返回一段js程式碼

window.wx_errcode=408;window.wx_code='';

再來看看網頁中嵌入的一段程式碼,這裡我省略了一些程式碼只留下比較重要的

!function() {
    function a(d) {
        jQuery.ajax({
            type: "GET",
            url: "https://long.open.weixin.qq.com/connect/l/qrconnect?uuid=011ZJt4N2TyhElXu" + (d ? "&last=" + d: ""),
            dataType: "script", //這裡是script型別
            cache: !1,
            timeout: 6e4,
            success: function(d, e, f) {
                var g = window.wx_errcode;//這裡為什麼是window.wx_errcode呢 因為返回的格式是script 內容是 window.wx_errcode=408;window.wx_code='';
                switch (g) {
                case 405://如果是405證明使用者已經同意授權登入 用js重定向並帶上code
                    var h = "http://www.jianshu.com/users/auth/wechat/callback";
                    h = h.replace(/&/g, "&"),
                    h += (h.indexOf("?") > -1 ? "&": "?") + "code=" + wx_code + "&state=123";
                    var i = b("self_redirect");
                    if (c) if ("true" !== i && "false" !== i) try {
                        document.domain = "qq.com";
                        var j = window.top.location.host.toLowerCase();
                        j && (window.location = h)
                    } catch(k) {
                        window.top.location = h
                    } else if ("true" === i) try {
                        window.location = h
                    } catch(k) {
                        window.top.location = h
                    } else window.top.location = h;
                    else window.location = h;
                    break;
                case 404:
                    jQuery(".js_status").hide(),
                    jQuery("#wx_after_scan").show(),
                    setTimeout(a, 100, g);
                    break;
                case 403:
                    jQuery(".js_status").hide(),
                    jQuery("#wx_after_cancel").show(),
                    setTimeout(a, 2e3, g);
                    break;
                case 402:
                case 500:
                    window.location.reload();
                    break;
                case 408:
                    setTimeout(a, 2e3)
                }
            },
            error: function(b, c, d) {
                var e = window.wx_errcode;
                408 == e ? setTimeout(a, 5e3) : setTimeout(a, 5e3, e)
            }
        })
    }
    ...
} ();

上面的程式碼是一段自執行函式,連結一開啟就會執行,在使用者掃碼之前請求是阻塞的success回撥都不會執行,如果使用者一直沒有掃描二維碼,請求在27秒內就會斷開連結這時就會去執行success回撥函式並且重新發起一個長連線重複以上步驟直到返回405

網頁中的二維碼解析後的結果是

https://open.weixin.qq.com/connect/confirm?uuid=0618LnlRCFd-jYeo

這個連結只有一個引數並且uuid和長連線請求的uuid是相同的,用遊覽器開啟會提示Scope 引數錯誤或沒有 Scope 許可權,只能用微信開啟才有用,微信的包不好抓希望有大神能夠指點指點

後端的開啟方式

重定向到微信頁面的開啟方式

https://open.weixin.qq.com/connect/qrconnect?
appid=wxbdc5610cc59c1631
&
redirect_uri=https%3A%2F%2Fxxx.xxx.com%2Fwechat%2Fcallback.do
&
response_type=code
&
scope=snsapi_login
&
state=3d6be0a4035d839573b04816624a415e#wechat_redirect

這裡需要變的引數是appid和redirect_url

訪問以上鍊接微信開發平臺會重定向到redirect_uri的網址上,並且帶上codestate引數,如果使用者沒有授權就不會有code引數,僅會帶上state引數

https://xxx.xxx.com?code=xxx&state=xxx

後臺根據code獲取使用者資訊封裝

獲取使用者資訊的步驟

  • 通過code獲取access_token
  • 通過access_token呼叫介面

這裡使用了weixin-java-tools工具來獲取使用者資訊
github地址 傳送門

public WxMpUser getWxUser(String code) {
        if (code == null) {
            return null;
        }
        WxMpOAuth2AccessToken wxMpOAuth2AccessToken = null;
        WxMpUser wxMpUser = null;
        try {
            wxMpOAuth2AccessToken = wxMpService.oauth2getAccessToken(code);
            wxMpOAuth2AccessToken = wxMpService.oauth2refreshAccessToken(wxMpOAuth2AccessToken.getRefreshToken());
            wxMpUser = wxMpService.oauth2getUserInfo(wxMpOAuth2AccessToken, null);
        } catch (WxErrorException e) {
            return null;
        }

        return wxMpUser;
    }