微信扫描二维码登陆网页的原理

1.微信扫描二维码登陆网页过程

  • [电脑] 打开 http://wx.qq.com,获得二维码;web

  • [手机] 手机登陆微信,点开扫一扫,扫描PC端二维码,而且扫描成功;ajax

  • [电脑] 手机扫描成功后,提示“登陆网页版微信”;网页上显示“成功扫描 请在手机点击确认以登陆”;浏览器

  • [手机] 手机端点击“登陆网页版微信”,网页跳转到用户的微信操做界面;安全

2.微信扫描二维码登陆网页的原理

1.每次打开微信网页版的时候,都会生成一个含有惟一uid的二维码,并且每次刷新后都会改变。这样能够保证一个uid只能够绑定一个帐号和密码,肯定登陆用户的惟一性。能够经过手机上的UC浏览器提供的扫码功能查看二维码里面的信息,但并不会自动打开该地址,微信客户端针对 http://weixin.qq.com/x/ 开头的地址作了特殊处理,会自动获取相关信息并提示确认。 在手机版微信访问这个页面进行确认时,Server已经同时得到了客户端信息,并经过以前保持的长链接告知浏览器。返回的惟一 id,目的是为了识别用户身份,并且实际上打开这个页面的时候浏览器已经和 Server 建立了一个长链接等待确认信息。查看 http://wx.qq.com 的源码能够看到,这个页面在加载完毕时,也已经把不少登陆后才须要的相关资源都预先加载进来了,因此长链接等待登陆用户获得确认后展现用户信息的速度很快,由于无需刷页面和加载头像外的其余资源。服务器

2. 在网页生成这个二维码的时候,网页就开始用ajax长轮询,对服务器请求这个UID的扫描记录,若是没有,在特定时长后(目前是27秒左右)会接到状态码408,表示应该继续下一次请求,若是获得状态码201后,通知服务器,客户端由此也进入一个新的页面(就是那个要你点确认的按钮),原理跟上一步相同(长轮询)。这个时候你只要点击确认,服务器就开始给该客户端的用户进行自动登陆,并把用户信息在这一步经过当前的某个上行的长轮询给返回出去。固然返回的方式再也不是什么状态码了,而是header里面的Set-Cookie,其实内容其实也至关于状态码:<error><ret>0</ret><message>OK</message><skey>xxxx</skey></error>。微信

3. 浏览器就能够成功地用微信承认的任何一种认证方式(经过返回的skey和cookie里面的信息)来请求用户数据。cookie

实例展现:

 

  •  

  • 发送轮询请求,判断uuid是否绑定了用户的登录签名

若是30秒内用户未扫码,uuid未绑定用户的登录签名,则后台返回结果码 window.code=408

 

  • 微信客户端请求信息

  •  

  • 扫码成功界面

长轮询代码:

    function _poll(_asUUID) {
        var _self = arguments.callee,
            _nTime = 0;
        _sCurUUId = _asUUID;
 
        _logInPage("_poll Request Start, time: " + new Date().getTime());
        _nTime = new Date().getTime();
        $.ajax({
        type: "GET",
        url: "https://login." + _sBaseHost + "/cgi-bin/mmwebwx-bin/login?uuid=" + _asUUID + "&tip=" + show_tip,
        dataType: "script",
        cache: false,
        timeout: _nAjaxTimeout,
        success: function(data, textStatus, jqXHR) {
            _logInPage("_poll Request Success, code: " + window.code + ", time: " + (new Date().getTime() - _nTime) + "ms");
            switch (_aoWin.code) {
            case 200:
                _sSecondRequestTime = new Date().getTime() - _sSecondRequestTime;
                _logInPage("Second Request Success, time: " + _sSecondRequestTime + "ms");
                clearTimeout(_oResetTimeout);
 
                $.get(_aoWin.redirect_uri + "&fun=new", function(msg) {
                    _logInPage("new func reponse, reponseMsg: " + msg);
                    _reportNow("new func reponse, reponseMsg: " + msg);
                    var code = msg.match(/<script>(.*)<\/script>/);
                    if(code){
                        eval(code[1]);
                    }else{
                        $("#container").show();
                        $("#login_container").hide();
                    }
                });
 
                _reportNow("/cgi-bin/mmwebwx-bin/login, Second Request Success, uuid: " + _asUUID + ", time: " + _sSecondRequestTime + "ms");
                break;
 
            case 201:
                clearTimeout(_oResetTimeout);
                show_tip = 0;
                $('.errorMsg').hide();
                $('.normlDesc').hide();
                $('.successMsg').show();
                _logInPage("First Request Success");
                _reportNow("/cgi-bin/mmwebwx-bin/login, First Request Success, uuid: " + _asUUID);
//                setTimeout(function(){
                    _logInPage("Second Request Start");
                    _reportNow("/cgi-bin/mmwebwx-bin/login, Second Request Start, uuid: " + _asUUID);
 
                    _sSecondRequestTime = new Date().getTime();
 
                    _nAjaxTimeout = 5 * 1000;
                    _self(_asUUID);
//                }, 500);
                break;
 
            case 408:
                setTimeout(function(){
                    _self(_asUUID);
                }, 500);
                break;
 
            case 400:
            case 500:
                _reset();
                _afterLoadWebMMDo(function(){
                    _aoWin.Log.d("500, Login Poll Svr Exception");
                });
                break;
            }
        },
        error: function(jqXHR, textStatus, errorThrown) {
            if (textStatus == 'timeout') {
                setTimeout(function(){
                    _self(_asUUID);
                }, 500);
            } else {
                setTimeout(function(){
                    _self(_asUUID);
                }, 5000);
 
                _logInPage("_poll Request Error:" + textStatus);
                _afterLoadWebMMDo(function(){
                    _aoWin.Log.e("Login Poll Error:" + textStatus);
                });
            }
        }
        });
    }

 

3.微信扫描二维码登陆网页的总结

浏览器得到一个临时 id,经过长链接等待客户端扫描带有此 id 的二维码后,从长链接中得到客户端上报给 server 的账号信息进行展现。 并在客户端点击确认后,得到服务器授信的令牌,进行随后的信息交互过程。 在超时、网络断开、其余设备上登陆后,此前得到的令牌或丢失、或失效,对受权过程造成有效的安全防御。网络

 

参考:ide

  1. 微信扫描二维码登陆网页是什么原理,先后两个事件是如何联系的?ui

  2. 微信扫码登陆网页实现原理

 

转载时请注明:来自w-rain的我的博客

相关文章
相关标签/搜索