掃碼登入的原理和實現
由於掃碼登入比賬號密碼登入更方便、快捷、靈活,在實際使用中更受到使用者的歡迎。
本文主要介紹了掃碼登入的原理及整體流程,包含了二維碼的生成/獲取、過期失效的處理、登入狀態的監聽。
掃碼登入的原理
整體流程
為方便理解,我簡單畫了一個 UML 時序圖,用以描述掃碼登入的大致流程!
總結下核心流程:
-
請求業務伺服器獲取用以登入的二維碼和 UUID。
-
通過 websocket 連線 socket 伺服器,並定時(時間間隔依據伺服器配置時間調整)傳送心跳保持連線。
-
使用者通過 APP 掃描二維碼,傳送請求到業務伺服器處理登入。根據 UUID 設定登入結果。
-
socket 伺服器通過監聽獲取登入結果,建立 session 資料,根據 UUID 推送登入資料到使用者瀏覽器。
-
使用者登入成功,伺服器主動將該 socker 連線從連線池中剔除,該二維碼失效。
關於客戶端標識
也就是 UUID,這是貫穿整個流程的紐帶,一個閉環登入過程,每一步業務處理都是圍繞該次的 UUD 進行處理的。UUID 的生成有根據 session_id 的也有根據客戶端 ip 地址的。個人還是建議每個二維碼都有單獨的 UUID,適用場景更廣一些!
關於前端和伺服器通訊
前端肯定是要和伺服器保持一直通訊的,用以獲取登入結果和二維碼狀態。看了下網上的一些實現方案,基本各個方案都有用的:輪詢、長輪詢、長連結、websocket。也不能肯定的說哪個方案好哪個方案不好,只能說哪個方案更適用於當前應用場景。個人比較建議使用長輪詢、websocket 這種比較節省伺服器效能的方案。
關於安全性
掃碼登入的好處顯而易見,一是人性化,再就是防止密碼洩漏。但是新方式的接入,往往也伴隨著新的風險。所以,很有必要再整體過程中加入適當的安全機制。例如:
- 強制 HTTPS 協議
- 短期令牌
- 資料簽名
- 資料加密
掃碼登入的過程演示
程式碼實現和原始碼後面會給出。
開啟 Socket 伺服器
訪問登入頁面
可以看到使用者請求的二維碼資源,並獲取到了qid
。
獲取二維碼時候會建立相應快取,並設定過期時間:
之後會連線 socket 伺服器,定時傳送心跳。
此時 socket 伺服器會有相應連線日誌輸出:
使用者使用 APP 掃碼並授權
伺服器驗證並處理登入,建立 session,建立對應的快取:
Socket 伺服器讀取到快取,開始推送資訊,並關閉剔除連線:
前端獲取資訊,處理登入:
掃碼登入的實現
注意:本 Demo 只是個人學習測試,所以並未做太多安全機制!
Socket 代理伺服器
使用 Nginx 作為代理 socke 伺服器。可使用域名,方便做負載均衡。本次測試域名:loc.websocket.net
websocker.conf
server { listen 80; server_name loc.websocket.net; root /www/websocket; index index.php index.html index.htm; #charset koi8-r; access_log /dev/null; #access_log /var/log/nginx/nginx.localhost.access.log main; error_log /var/log/nginx/nginx.websocket.error.log warn; #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } location / { proxy_pass http://php-cli:8095/; proxy_http_version 1.1; proxy_connect_timeout 4s; proxy_read_timeout 60s; proxy_send_timeout 12s; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; } }Socket 伺服器
使用 PHP 構建的 socket 伺服器。實際專案中大家可以考慮使用第三方應用,穩定性更好一些!
QRServer.php