Created by Wang, Jerry, last modified on Dec 10, 2014
在电脑上使用微信时,你可能已经发现微信不提供传统的账号密码登陆,取而代之的是通过扫描二维码进行登陆。今天就要研究下次登陆方式微信时如何实现的?
每次用户打开PC端登陆请求,系统返回一个唯一的uid,并将uid的信息绘制成二维码返回给用户。这里的uid一定是唯一的,否则就会造成你登陆了其他用户的账号或者其他用户登陆你的账号。
当用户使用登陆后的微信扫描该二维码的时候,会将这个uid和手机上的微信账号及密码产生的token进行绑定,并上传到服务器。
WEB通过JS不断的向后端发起请求,查询有没有关于uid的登陆记录(uid和token是否存在于服务器上)。实现代码可以从微信页面获取:
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>/);</div><div data-lake-id="b9a355b9c9bf8d2a3cdb01514fe34a08"> if(code){</div><div data-lake-id="0926c3292a8fedad82556a5e9d7f1961"> eval(code[1]);</div><div data-lake-id="fa3b1044b0bb322ae3081551293a6ad3"> }else{</div><div data-lake-id="13f5d4e7cd3d4924ed4e7f8cd2409f17"> $("#container").show();</div><div data-lake-id="4bedd0c9d09edab4e2851f94e80ec4c1"> $("#login_container").hide();</div><div data-lake-id="d044034d51070ffb0391624ef08d84e9"> }</div><div data-lake-id="10567c2100799dc2f5f53aebcd4bdac6"> });</div><div data-lake-id="5c41ca7e63050b7e08052b3f762034d4"> _reportNow("/cgi-bin/mmwebwx-bin/login, Second Request Success, uuid: " + _asUUID + ", time: " + _sSecondRequestTime + "ms");</div><div data-lake-id="f046fe4528bea0a9f636a9b2366edb06"> break;</div><div data-lake-id="24021de52039f405cddaa1ef7dfcd07f"> case 201:</div><div data-lake-id="dccb43a316051610ed6095b6378e4e2f"> clearTimeout(_oResetTimeout);</div><div data-lake-id="e9e2af7030101bf79d041a04897b2e93"> show_tip = 0;</div><div data-lake-id="9e88080ab45352524cfd53fac48ab049"> $('.errorMsg').hide();</div><div data-lake-id="0c95368c6fd99125856fb6ec6b3aea0c"> $('.normlDesc').hide();</div><div data-lake-id="2308892aea45b9e79b8c3a9dbf8b3ac4"> $('.successMsg').show();</div><div data-lake-id="d241866b1485fbb10787030b431e944a"> _logInPage("First Request Success");</div><div data-lake-id="38bde0b15ac106e81245a9416ff9b7ec"> _reportNow("/cgi-bin/mmwebwx-bin/login, First Request Success, uuid: " + _asUUID);</div><div data-lake-id="a992af24531bc3f29d789fe3cca5aaa9">// setTimeout(function(){</div><div data-lake-id="9cd1eb31a1cc9c2377102b17d541faa4"> _logInPage("Second Request Start");</div><div data-lake-id="ba0ccad1e5233baeeda619b9833c5d7f"> _reportNow("/cgi-bin/mmwebwx-bin/login, Second Request Start, uuid: " + _asUUID);</div><div data-lake-id="a7bfa244e49a445627053a2b283ad15d"> _sSecondRequestTime = new Date().getTime();</div><div data-lake-id="846471f9da5cff4974e3a9826f5b12b5"> _nAjaxTimeout = 5 * 1000;</div><div data-lake-id="20d33dc827ea39c3dc471b5e66ade101"> _self(_asUUID);</div><div data-lake-id="66f738295888ea5e9492dd8d5a1aa518">// }, 500);</div><div data-lake-id="0824c5b9d99acf817e55ce9ff6758de2"> break;</div><div data-lake-id="9ac025557f0fd0e6adc5b086b931a602"> case 408:</div><div data-lake-id="fe54828364adb891d667547a293ab22c"> setTimeout(function(){</div><div data-lake-id="43f47023a35e4f4c50ab1a724f7c016a"> _self(_asUUID);</div><div data-lake-id="9ae775df61a912d8f337259e08b52c97"> }, 500);</div><div data-lake-id="bafa69e12909082d0c6b5eb88a7d95b9"> break;</div><div data-lake-id="4be94e2cf1fc1cf2dd6f69f39de2407f"> case 400:</div><div data-lake-id="6b42d1435b532c89db1efce8d63c1adc"> case 500:</div><div data-lake-id="0b6a4c7008362f00aead7afff2df7930"> _reset();</div><div data-lake-id="aa2625184c55f92b027c22f9c26fe074"> _afterLoadWebMMDo(function(){</div><div data-lake-id="0a43d504d41063e43b141568dc9576e9"> _aoWin.Log.d("500, Login Poll Svr Exception");</div><div data-lake-id="c35a0662784da1dc6f19e26b77d61a28"> });</div><div data-lake-id="036950e36e4ecae4b044a0d15d3a5568"> break;</div><div data-lake-id="a77f1db6063c2d2cc5763584378d5e65"> }</div><div data-lake-id="40e2f0285910f97756ad006d2558a6ac"> },</div><div data-lake-id="006e6a8f3d5abef894c087a89571fb51"> error: function(jqXHR, textStatus, errorThrown) {</div><div data-lake-id="6f6b5a53192d4489c686173f8a182bd6"> if (textStatus == 'timeout') {</div><div data-lake-id="33631c48a76e813686b994b80c719a6d"> setTimeout(function(){</div><div data-lake-id="5393f09e0936a8181e03995912147389"> _self(_asUUID);</div><div data-lake-id="bd3a5ac4519632f05914eb9c58510cb8"> }, 500);</div><div data-lake-id="39d3ebd11d9da78f936b5a993b2c4dac"> } else {</div><div data-lake-id="d10440d3ba5aee2fc705ccecadd96e8e"> setTimeout(function(){</div><div data-lake-id="9395e8bd5886ba94865adfe7c4da1845"> _self(_asUUID);</div><div data-lake-id="65085d087bca65d04b14ac70833c979f"> }, 5000);</div><div data-lake-id="ef28bc0a41af85ae8fb3ceee3f80efbc"> _logInPage("_poll Request Error:" + textStatus);</div><div data-lake-id="2a5d85d4613977859d7101b4dca6c200"> _afterLoadWebMMDo(function(){</div><div data-lake-id="4e79fc22c51d50f2423c0272e183a3bf"> _aoWin.Log.e("Login Poll Error:" + textStatus);</div><div data-lake-id="c37b61433368aca2cf2cb516e60d43b4"> });</div><div data-lake-id="3b40acbf02e2f85913ba091d551fa882"> }</div><div data-lake-id="abe1a920ce8ecb275c3cfee2d47d35ff"> }</div><div data-lake-id="b8be92c949ecbad79c28d82c3c5aa5c4"> });</div><div data-lake-id="db7c6dfadf22aedb663d3e9b33ee2863"> }</div><div data-lake-id="31f32fe27cd39fdd0491373f27a276d7"><span data-card-type="inline" data-ready-card="image" data-card-value="data:%7B%22src%22%3A%22https%3A%2F%2Fucc.alicdn.com%2Fpic%2Fdeveloper-ecology%2F4ffd1deb58d04f61940da851db487d9e.png%22%2C%22originWidth%22%3A776%2C%22originHeight%22%3A741%2C%22name%22%3A%22image.png%22%2C%22size%22%3A68578%2C%22display%22%3A%22inline%22%2C%22align%22%3A%22left%22%2C%22linkTarget%22%3A%22_blank%22%2C%22status%22%3A%22done%22%2C%22style%22%3A%22none%22%2C%22search%22%3A%22%22%2C%22margin%22%3A%7B%22top%22%3Atrue%2C%22bottom%22%3Atrue%7D%2C%22width%22%3A776%2C%22height%22%3A741%7D"></span></div><div data-lake-id="7bffbee990e10b913517a3057635081f"><span data-card-type="inline" data-ready-card="image" data-card-value="data:%7B%22src%22%3A%22https%3A%2F%2Fucc.alicdn.com%2Fpic%2Fdeveloper-ecology%2Fc89f090e38e6487c85b25f7fdab0dd79.png%22%2C%22originWidth%22%3A764%2C%22originHeight%22%3A764%2C%22name%22%3A%22image.png%22%2C%22size%22%3A55638%2C%22display%22%3A%22inline%22%2C%22align%22%3A%22left%22%2C%22linkTarget%22%3A%22_blank%22%2C%22status%22%3A%22done%22%2C%22style%22%3A%22none%22%2C%22search%22%3A%22%22%2C%22margin%22%3A%7B%22top%22%3Atrue%2C%22bottom%22%3Atrue%7D%2C%22width%22%3A764%2C%22height%22%3A764%7D"></span></div><div data-lake-id="3d522a779e34efbd9f0724be4c4dcb6e">网页客户端每500毫秒就向服务器发起ssl请求,请求当前二维码的登陆信息,如果返回结果201,则说明已经获取扫描二维码终端相同的账号登陆授权,当返回其他结果时,将在500毫秒之后重新发起请求。</div><div data-lake-id="eb21508d9442911f4569bd6ec989ebcb">类似微信登陆场景应用场景还是很多,比如通过二维码进行设备间的授权。比如使用手机遥控 装有android系统的电视盒等。</div><div data-lake-id="fda87f139179b7b9837f0b28e9feb1dd"><span data-card-type="inline" data-ready-card="image" data-card-value="data:%7B%22src%22%3A%22https%3A%2F%2Fucc.alicdn.com%2Fpic%2Fdeveloper-ecology%2F10f3f92cc1e64990b6722764d6991403.png%22%2C%22originWidth%22%3A788%2C%22originHeight%22%3A501%2C%22name%22%3A%22image.png%22%2C%22size%22%3A201218%2C%22display%22%3A%22inline%22%2C%22align%22%3A%22left%22%2C%22linkTarget%22%3A%22_blank%22%2C%22status%22%3A%22done%22%2C%22style%22%3A%22none%22%2C%22search%22%3A%22%22%2C%22margin%22%3A%7B%22top%22%3Atrue%2C%22bottom%22%3Atrue%7D%2C%22width%22%3A788%2C%22height%22%3A501%7D"></span></div><div data-lake-id="b4929d67f01c44f1f76967c1da4d8423"><br /></div>