一圖搞懂Web應用的單點登錄
- 2021 年 12 月 30 日
- 筆記
單點登錄即Signle Sign On,簡稱SSO。其解決的是用戶在多個站點之間跳轉時需要頻繁登錄的問題,比如用戶登錄了天貓,就應該無需再使用帳號登錄淘寶,它們之間是可以相互信任的,應該自動同步登錄狀態。從這點上看單點登錄技術的本質是登錄狀態在多個站點之間的擴散機制。
先來看下單個程式的登錄處理流程,這裡以Web應用程式為例。在單個Web應用程式中用戶通過瀏覽器提交帳號資訊到後端服務,後端服務驗證帳號的有效性,驗證通過後在後端創建一個Session,用來維持用戶的登錄狀態,然後向前端返回一個SessionId,前端將這個SessionId保存起來,這個保存操作一般是寫入當前域名對應的Cookie,之後每次請求Web頁面的時候都要攜帶這個SessionId,後端服務根據這個SessionId就能識別是哪個用戶,然後就可以進行對應的業務處理。具體登錄流程如下圖所示:
那如何在多個站點之間共享登錄狀態呢?如果是同一個頂級域名下的不同子域名站點,可以通過共享Cookie的方式,具體操作就是設置Cookie的Domain屬性為同一個頂級域名,則各個站點都能獲取到這個Cookie,也就能獲取到同一個Session,實現登錄狀態的共享。不過這種方式的普適性不太好,不同的域名之間就做不到,而且共享Cookie安全性上也會有點問題。
本文將介紹一種更通用的單點登錄方式,通過引入一個SSO站點,所有的登錄請求和登錄狀態同步請求都交給這個站點來處理。這裡假設有兩個站點需要同步登錄狀態:站點A 和 站點B,用戶訪問站點A時沒有登錄過,需要在SSO站點先登錄,然後登錄狀態同步到站點A,訪問站B時,因為用戶已經登錄過,所以只需要將登錄狀態同步到站點B即可。一圖勝千言,下面給出詳細的時序圖,並做一些關鍵步驟說明,具體過程稍微有些複雜,不過仔細閱讀,還是比較容易理解的。
步驟5: 用戶在業務站點未登陸時,統一重定向到SSO站點的登錄頁面。這裡有一點需要注意:重定向時需要攜帶用戶訪問A站點的地址,這樣成功登錄後才能跳轉回來。
步驟6和步驟27: 重定向到SSO站點時,有兩點需要注意:一是要檢查來源,如果不是允許的業務站點,則應該拒絕請求,這樣比較安全;二是會檢查用戶在SSO站點的登錄狀態,如果登錄過,瀏覽器會在HTTP請求頭中攜帶SessionId的Cookie,根據這個SessionId可以判斷用戶登錄狀態是否有效,如果有效則給業務站點返回一個Ticket,如果無效則返回登錄頁面內容,需要用戶先通過帳號登錄成功,然後再給業務站點返回Ticket。
步驟15和步驟30: 業務站點收到SSO站點的Ticket之後,還要使用事先分配好的密鑰計算一個簽名,這個密鑰每個站點應該不同,業務站點後台攜帶這個Ticket和簽名去SSO站點進行驗證。Ticket是SSO站點發放的,自然能夠驗證其有效性;密鑰也是SSO站點發放的,根據簽名的計算規則再算一遍,對比下就知真偽了。然後告知業務站點你可以登錄了,並發送必要的用戶資訊。之所以會有這個步驟,是因為來源的驗證不是那麼可靠,密鑰每家獨一份,安全性就高了很多。
步驟18和步驟33: 業務站點都需要創建自己的用戶Session,然後在瀏覽器寫入對應業務站點的SessionId Cookie。這個Session在服務端可以分別存儲,如果業務規模不大也可以使用同一份存儲,統一存儲時登錄狀態可以統一管理。
當前有很多的站點使用JWT做登錄認證,這樣有個好處就是分散式環境下不需要集中認證,每個部署節點都擁有完全的認證能力,不過如果需要註銷用戶的時候,就很難實現同步註銷。有一些解決方案,比如認證Token的生存期短一點,再增加一個刷新Token,刷新Token時訪問集中的認證服務;或者使用一個高效的黑名單機制,每次都檢查黑名單等。如果業務規模不是很大,都不如統一Session的機制簡單,比如使用Redis存儲Session資訊,輕鬆處理千級萬級並發。
以上就是本文的全部內容了,重點就是那張單點登錄的時序圖,想不明白的時候可以多擼幾遍,如有錯漏歡迎指正。
收穫更多架構知識,請關注公眾號 螢火架構。原創內容,轉載請註明出處。