详解二维码登录的原理

互联网 17-5-16
这篇文章主要大家详细解析了微信QQ的二维码登录原理js代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

在很多地方就是都出现了使用二维码登录,二维码付款,二维码账户等应用(这里的二维码种马,诈骗就不说了),二维码验证,多终端辅助授权应用开始多起来,这里先说下啥是二维码,其实二维码就是存了二进制数据的黑白图片,当出现要求二维码登录的时候,服务器会生成一条临时的唯一的二维码信息,发送到客户端以二维码(图片)的形式写入到网页,然后你就会看到统一的四个方形的二维码,如果做的好这个二维码信息应该是有时效的,这里暂且不考虑这些,就简单的微信登录作为例子看看吧:

首先说下整个授权流程:

在客户端网页中会不断向服务器发送https连接,并且这里传输很少的数据之后就断开连接了,下面看下微信网页中这个login1c709c.js文件:

(function($, _aoWin) {     _aoWin.QRLogin = {};   _aoWin.LoginLog = "";   var _sBaseHost = "",   _oLoginQrCodeImg = document.getElementById("loginQrCode");   if (document.domain == "qq.com") {   _sBaseHost = "weixin.qq.com";   } else if(location.hostname.match(/(wechat\.com)$/)){   _sBaseHost = "wechat.com";   }else{   _sBaseHost = "wechatapp.com";   }     var show_tip = 1,   _sCurUUId,   _oResetTimeout,   _aWebMMCallbacks = [],   _oDetactWebMMInterval = setInterval(function(){    if(_aoWin.WebMM){    clearInterval(_oDetactWebMMInterval);    var callback;    while(callback = _aWebMMCallbacks.shift()){     if(typeof(callback) != "function") continue;     callback();    }    }   }, 1000);     function _logInPage(_asLog){   _aoWin.LoginLog = LoginLog + _asLog + "\n";   }     function _afterLoadWebMMDo(callback){   if(!_aoWin.WebMM){    _aWebMMCallbacks.push(callback);   }else{    callback();   }   }     function _reportNow(text){   _logInPage(text);   _afterLoadWebMMDo(function(){    WebMM.ossLog({Text: text});    WebMM.flushOssLog();   });   }     var reLoadQRImgCount = 0,   loadQRCodeTime = 0,   loadQRImgSucc = function(){    clearInterval(loadQRImgWatchDog);    _logInPage("Load QRCode Success, time=" + (new Date().getTime() - loadQRCodeTime) + "ms, reload count: " + reLoadQRImgCount);   },   loadQRImgFail = function(img){    _reportNow("Load QRcode fail!" + status + ", src: " + img.src + ", time: " + (new Date().getTime() - loadQRCodeTime) + "ms");   },   loadQRImgWatchDog = null;   function _loadQRImg(uuid) {   _poll(uuid);   _logInPage("Load QRCode Start");   loadQRCodeTime = new Date().getTime();     _oLoginQrCodeImg.onload = function(){    loadQRImgSucc();    _oLoginQrCodeImg.onload = null;   };   _oLoginQrCodeImg.onerror = function(){loadQRImgFail(this)};   _oLoginQrCodeImg.src = "https://login."+_sBaseHost+"/qrcode/"+uuid+"?t=webwx";     loadQRImgWatchDog = setInterval(function(){    if (reLoadQRImgCount >= 5) {    _reset();    return;    }    reLoadQRImgCount++;      var _img = new Image();    _img.onload = function () {    if(!_oLoginQrCodeImg.onload) return;      _oLoginQrCodeImg.onload = null;    _oLoginQrCodeImg.src = this.src;//replace    loadQRImgSucc();    };    _img.onerror = function(){loadQRImgFail(this)};    _img.src = _oLoginQrCodeImg.src + "&r=" + new Date().getTime();   }, 5000);   }     var _sSecondRequestTime = 0,   _nAjaxTimeout = 100 * 1000,   _nNewLoginFuncErrCount = 0;   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);      var _fNewLoginFunc = function(){     $.ajax({     url: _aoWin.redirect_uri + "&fun=new",//new login page     type: "GET",     success:function(msg) {      _logInPage("new func reponse, reponseMsg: " + msg);      var code = msg.match(/<script>(.*)<\/script>/);      var skey=msg.match(/<skey>(.*)<\/skey>/);      if(code){      eval(code[1]);      }else{      $("#container").show();      $("#login_container").hide();      }      if(skey && skey[1]){      WebMM.model("account").setSkey(skey[1]);      }     },     error:function(jqXHR, textStatus, errorThrown){      _nNewLoginFuncErrCount++;      if(_nNewLoginFuncErrCount > 5){      if(confirm("Call new login page func error, refresh?")){location.reload()}      return;      }      _reportNow(_aoWin.redirect_uri + " New login page func error: " + textStatus +" retryCount:" + _nNewLoginFuncErrCount);      setTimeout(_fNewLoginFunc, 500);     }     });    };    _fNewLoginFunc();      _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();    _reportNow("/cgi-bin/mmwebwx-bin/login, First Request Success, uuid: " + _asUUID);    _reportNow("/cgi-bin/mmwebwx-bin/login, Second Request Start, uuid: " + _asUUID);      _sSecondRequestTime = new Date().getTime();      //_nAjaxTimeout = 5 * 1000;    _self(_asUUID);    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);    });   }   }   });   }     var getUUIDCount = 0,   _getUUIDWatchDog,   _bGetUUIDSuccess = false;//ajax successִ   function _getUUID() {   getUUIDCount++;   var _self = arguments.callee,    _loadError = function(errorText){    _reportNow("Load UUID Error! ErrorText: " + errorText + " getUUIDCount=" + getUUIDCount);    if(getUUIDCount > 5){     if (confirm("Load uuid error. Refresh?")) {     location.reload();     }    }    setTimeout(function(){     _self();    }, 500);    };     clearTimeout(_getUUIDWatchDog);   _getUUIDWatchDog = setTimeout(function(){    if(!_aoWin.QRLogin.code){    _logInPage("GetUUID Timeout, WatchDog Run");    _self();    }   }, 10000);     $.ajax({    type: "GET",    url: "https://login." + _sBaseHost + "/jslogin?appid=wx782c26e4c19acffb&redirect_uri="+encodeURIComponent(location.protocol+"//"+location.host+"/cgi-bin/mmwebwx-bin/webwxnewloginpage")+"&fun=new&lang=" + document.lang,    dataType: "script",    cache: false,    success : function(){    clearTimeout(_getUUIDWatchDog);    if(_bGetUUIDSuccess) return;    if (_aoWin.QRLogin && _aoWin.QRLogin.code == 200) {     _logInPage("GetUUID Success, UUID=" + QRLogin.uuid);     _bGetUUIDSuccess = true;       clearTimeout(_oResetTimeout);     _oResetTimeout = setTimeout(function(){     location.reload();//Note: Don't run _reset(). If you run _reset(), there will may have many _poll request, as they get 408 return code     }, 5 * 60 *1000);//5 mins       _loadQRImg(QRLogin.uuid);    } else {     var QRLoginCode = (_aoWin.QRLogin && _aoWin.QRLogin.code) ? _aoWin.QRLogin.code : "None";     _logInPage("GetUUID Error, QRLogin.code=" + QRLoginCode);     _loadError("QRLogin.code= " + QRLoginCode);    }    },    error : function(xhr, textStatus, errorThrown){    _logInPage("GetUUID Error, textStatus=" + textStatus);    _loadError(textStatus);    }   });   }     function _reset(){   location.reload();   }     if ($("#login_container").is(":visible") ) {   _getUUID();   }        var _bHadLog = false;   function _ossLog() {   if (_bHadLog) return;   _bHadLog = true;   var _sUvid = document.cookie.match(new RegExp( "(^| )"+"webwxuvid"+"=([^;]*)(;|$)"));   if(!_sUvid || _sUvid.length < 3) return;   _sUvid = _sUvid[2];   (new Image()).src = "/cgi-bin/mmwebwx-bin/webwxstatreport?funkey=indexdemo&uvid="+_sUvid+"&uuid="+_sCurUUId;   }       if($("img.guide").length > 0) {   var _nTimer = 0,   _oGuide$ = $(".guide"),   _oGuideTrigger$ = $("#guideTrigger, #tipTrigger"),   _oMask$ = $(".mask");     function _back() {   _nTimer = setTimeout(function() {   _oMask$.stop().animate({opacity:0}, function(){$(".mask").hide()});   _oGuide$.stop().animate({marginLeft:"-120px",opacity:0}, "400", "swing",function(){   _oGuide$.hide();   });   }, 100);   }     /*guide*/   _oGuide$.css({"left":"50%", "opacity":0});   _oGuideTrigger$.css({"backgroundColor":"white", "opacity":"0"});   _oGuideTrigger$.mouseover(function(){   clearTimeout(_nTimer);   _oMask$.show().stop().animate({"opacity":0.2});   _oGuide$.css("display", "block").stop().animate({marginLeft:"+168px", opacity:1}, 900, "swing", function() {   _oGuide$.animate({marginLeft:"+153px"}, 300);   });   _ossLog();   }).mouseout(_back);     _oGuide$.mouseover(function(){   clearTimeout(_nTimer);   }).mouseout(_back);   }  })(jQuery, window);

细读js之后,你就会从网页客户端这边看到请求登录的一面,网页客户端每隔500毫秒就向服务器发起ssl请求,请求当前的二维码是否被其他客户端(手机)授权,如果返回结果是201,就是说明已经获取扫描二维码终端相同的账号登录授权,如果是其他情况就再隔500毫秒再循环发请求。这个过程会一直持续到二维码被扫描通过或者二维码超时(失效)为止。 【相关推荐】

1. 特别推荐:“php程序员工具箱”V0.1版本下载

2. 微信小程序完整源码下载

3. 微信小程序demo:仿网易云音乐

以上就是详解二维码登录的原理的详细内容,更多内容请关注技术你好其它相关文章!

来源链接:
免责声明:
1.资讯内容不构成投资建议,投资者应独立决策并自行承担风险
2.本文版权归属原作所有,仅代表作者本人观点,不代表本站的观点或立场
标签: 二维码
上一篇:php获取远程图片并下载保存到本地的方法分析 下一篇:Java实现微信公众号和扫码支付的案例

相关资讯