微信掃碼登入是經常用到的的騷操作,但是,其實現的思路是怎樣的,可能很多人都沒有去思考過。記得曾經在一次面試當中,面試官就曾問過微信掃碼登入的實現思路,這次,以微信讀書網頁版掃碼登入為例子,聊聊我對微信掃碼登入技術實現思路一些思考。
以谷歌瀏覽器來做本次分析,開啟F12,準備隨時觀察http連線狀況。
接下來用谷歌瀏覽器開啟網頁版微信讀書,點選登入,會彈出一個二維碼:
可以看到,在二維碼彈出來的時候,前端呼叫了後端兩個介面,一個是getuid(),一個是getinfo(),這裡面涉及到哪些邏輯實現呢?
稍微思考一下,其實很好理解,每個隨機生成的二維碼,其實都是一個uuid碼,也就是說,在點選登入的時候,會執行一個getuid()方法,去呼叫後端API:web/login/getuid,然後返回一個隨機生成的uuid碼。當這個uuid碼返回到前端上時,就會以二維碼的形式展示。根據uuid如何生成二維碼,我後面再寫一篇小白文來分析下。
在谷歌瀏覽器F12調出的控制檯頁面,點選getuid(),在右邊欄的Preview框裡,可看到該方法返回一個隨機生成的uuid:38e673a9-5bd3-4f0c-ba2f-62ab376372a9
返回uuid的同時,還呼叫了另一個getinfo()方法——可見,這應該是getuid呼叫成功後的回撥方法,也就是當getuid()執行成功後,在得到一個uid時,就立馬呼叫getinfo()方法,同時將生成的uid當做引數傳給getinfo(),讓其去訪問後端API。
當沒有用手機微信進行掃碼操作時,會看到getinfo()一直沒有返回值,這時,它傳給後端的uuid正在做輪詢查詢操作,在某段時間內,若沒有輪詢成功,就會斷開連線,介面呼叫失敗。
到這裡,可以簡單歸納下網頁版微信登入頁面生成二維碼的流程,即,在點選登入按鈕時,程式碼層面會執行getuid()方法去呼叫後端API介面,即“https://weread.qq.com/web/login/getuid”,後臺將隨機生成一個唯一uid返回。前端得到正常返回狀態後,就會將引數傳給getuid的回撥方法getinfo({"uid":"38e673a9-5bd3-4f0c-ba2f-62ab376372a9"}),該getinfo方法會將uid引數傳給後端API介面“https://weread.qq.com/web/login/getinfo”,這時,後端內部將一直做輪詢拿uid去redis查詢,若能查詢成功,即登入成功,反之,則連線超時失敗。
下面用兩段虛擬碼來說明下大概程式碼邏輯:
一.前端React獲取uuid並回撥給getinfo()虛擬碼:
1 export const getuid=(params={},queue='getuid')=>dispatch=>{
2 http.post({
3 url:'https://weread.qq.com/web/login/getuid',
4 params:params,
5 queue:queue,
6 callback:(res)=>{
7 //getuid方法執行成功,返回{uid: "38e673a9-5bd3-4f0c-ba2f-62ab376372a9"},
//回撥執行getinfo()
8 dispatch(getinfo({uid:res.uid}))
9 }
10 });
11 }
12
13 export const getinfo=(params={},queue='getinfo')=>dispatch=>{
14 http.get({
15 url:'https://weread.qq.com/web/login/getinfo',
16 params:params,
17 queue:queue,
18 callback:(res)=>{
19 //若登入成功,應該重定向到已登入狀態的主頁
20 }
21 });
22 }
二.後端API介面/web/login/getinfo虛擬碼:
1 public String getinfo(String uid){
2 ......
3 //迴圈查詢uid在redis裡是否存在值
4 while(true){
5 String user=redisTemplate.opsForValue().get(uid);
6 if(user!=null){
7 return user;
8 }
9 }
10 ......
11 }
用一個時序圖來簡單表示這個過程:
那麼,什麼時候才能通過uid去redis查詢才能得到返回值呢?
這時候,就要說到掃碼階段了。
當getinfo(String uid)介面在輪詢查詢redis是否有key為uid的值時,使用者拿出手機,在二維碼有效時間內,用微信掃一掃進行掃碼操作,這時,手機上就會出現該頁面展示:
若點選登入,網頁版微信讀書就會重新整理,進入到已登入狀態的首頁。
這個過程很好理解,即在掃碼後,手機端會從二維碼中獲取到uid,這時,若點登入,就會將uid與微信使用者資訊一塊包裝成json格式post提交給後端,然後在後端介面中,將以uid:user的key-value形式set插入到redis資料庫。這時,另一邊正在以uid當做key值輪詢去redis是否有值的getinfo(String uid)方法,通過類似redisTemplate.opsForValue().get(uid)的方式,正好就能通過uid把剛插入redis的user資訊查詢出來,最後返回給PC端的微信讀書前端,即登入成功。
最後,完整的流程可以時序圖這樣表示:
PC端微信讀書登入成功的時候,頁面重新做了重新整理,應該是在後臺做了介面重定向,具體如何重定向,感興趣的朋友可以自行思考研究,微信掃碼登入大體上就是這個思路,但細節方面應該會有更多相關校驗在裡面。
這裡主要是分析下它的整體實現思路。
值得提一點是,PC端微信讀書前端其實做了反除錯,但沒關係,它這個反除錯的做法很容易破解,可參考我的做法,即開啟谷歌瀏覽器,按F12,調出控制檯,把這個圖示點亮,就可以關閉微信讀書前端自帶的反除錯設定了。