作者:一葉知秋
https://dwz.cn/d90vKSJE
單點登錄在現在的系統架構中廣泛存在,他將多個子系統的認證體系打通,實作了一個入口多處使用,而在架構單點登錄時,也會遇到一些小問題,在不同的應用環境中可以采用不同的單點登錄實作方案來滿足需求,
我將以我所遇到的應用環境以及在其中所經歷的各個階段與大家分享,若有不足,希望各位不吝賜教,
一、共享Session
共享Session可謂是實作單點登錄最直接、最簡單的方式,將用戶認證資訊保存于Session中,即以Session記憶體儲的值為用戶憑證,這在單個站點內使用是很正常也很容易實作的,而在用戶驗證、用戶資訊管理與業務應用分離的場景下即會遇到單點登錄的問題,在應用體系簡單,子系統很少的情況下,可以考慮采用Session共享的方法來處理這個問題,

這個架構我使用了基于Redis的Session共享方案,將Session存盤于Redis上,然后將整個系統的全域Cookie Domain設定于頂級域名上,這樣SessionID就能在各個子系統間共享,分布式Session共享解決方案,這篇推薦大家看下,
這個方案存在著嚴重的擴展性問題,首先,ASP.NET的Session存盤必須為SessionStateItemCollection物件,而存盤的結構是經過序列化后經過加密存盤的,
并且當用戶訪問應用時,他首先做的就是將存盤容器里的所有內容全部取出,并且反序列化為SessionStateItemCollection物件,
這就決定了他具有以下約束:
1.Session中所涉及的型別必須是子系統中共同擁有的(即程式集、型別都需要一致),這導致Session的使用受到諸多限制;
2.跨頂級域名的情況完全無法處理;
二、基于OpenId的單點登錄
這種單點登錄將用戶的身份標識資訊簡化為OpenId存放于客戶端,當用戶登錄某個子系統時,將OpenId傳送到服務端,服務端根據OpenId構造用戶驗證資訊,多用于C/S與B/S相結合的系統,流程如下:

由上圖可以看到,這套單點登錄依賴于OpenId的傳遞,其驗證的基礎在于OpenId的存盤以及發送,
1.當用戶第一次登錄時,將用戶名密碼發送給驗證服務;
2.驗證服務將用戶標識OpenId回傳到客戶端;
3.客戶端進行存盤;
4.訪問子系統時,將OpenId發送到子系統;
5.子系統將OpenId轉發到驗證服務;
6.驗證服務將用戶認證資訊回傳給子系統;
7.子系統構建用戶驗證資訊后將授權后的內容回傳給客戶端,
這套單點登錄驗證機制的主要問題在于他基于C/S架構下將用戶的OpenId存盤于客戶端,在子系統之間發送OpenId,而B/S模式下要做到這一點就顯得較為困難,為了處理這個問題我們將引出下一種方式,這種方式將解決B/S模式下的OpenId的存盤、傳遞問題,
三、基于Cookie的OpenId存盤方案
我們知道,Cookie的作用在于充當一個資訊載體在Server端和Browser端進行資訊傳遞,而Cookie一般是以域名為分割的,例如a.xxx.com與b.xxx.com的Cookie是不能互相訪問的,但是子域名是可以訪問上級域名的Cookie的,即a.xxx.com和b.xxx.com是可以訪問xxx.com下的Cookie的,于是就能將頂級域名的Cookie作為OpenId的載體,

驗證步驟和上第二個方法非常相似:
1、 在提供驗證服務的站點里登錄;
2、 將OpenId寫入頂級域名Cookie里;
3、 訪問子系統(Cookie里帶有OpenId)
4、 子系統取出OpenId通過并向驗證服務發送OpenId
5、 回傳用戶認證資訊
6、 回傳授權后的內容
在以上兩種方法中我們都可以看到通過OpenId解耦了Session共享方案中的型別等問題,并且構造用戶驗證資訊將更靈活,子系統間的驗證是相互獨立的,但是在第三種方案里,我們基于所有子系統都是同一個頂級域名的假設,而在實際生產環境里有多個域名是很正常的事情,那么就不得不考慮跨域問題究竟如何解決,
四、B/S多域名環境下的單點登錄處理
在多個頂級域名的情況下,我們將無法讓各個子系統的OpenId共享,處理B/S環境下的跨域問題,我們首先就應該想到JSONP的方案,

驗證步驟如下:
1、 用戶通過登錄子系統進行用戶登錄;
2、 用戶登錄子系統記錄了用戶的登錄狀態、OpenId等資訊;
3、 用戶使用業務子系統;
4、 若用戶未登錄業務子系統則將用戶跳轉至用戶登錄子系統;
5、 用戶子系統通過JSONP介面將用戶OpenId傳給業務子系統;
6、 業務子系統通過OpenId呼叫驗證服務;
7、 驗證服務回傳認證資訊、業務子系統構造用戶登錄憑證;(此時用戶客戶端已經與子業務系統的驗證資訊已經一一對應)
8、 將用戶登錄結果回傳用戶登錄子系統,若成功登錄則將用戶跳轉回業務子系統;
9、 將授權后的內容回傳客戶端;
五、安全問題
經過以上步驟,跨域情況下的單點登錄問題已經可以得到解決,而在整個開發程序初期,我們采用用戶表中紀錄一個OpenId欄位來保存用戶OpenId,而這個機制下很明顯存在一些安全性、擴展性問題,這個擴展性問題主要體現在一個方面:OpenId的安全性和用戶體驗的矛盾,
整個單點登錄的機制決定了OpenId是會出現在客戶端的,所以OpenId需要有過期機制,假如用戶在一個終端登錄的話可以選擇在用戶每次登錄或者每次退出時重繪OpenId,而在多終端登錄的情況下就會出現矛盾:當一個終端重繪了OpenId之后其他終端將無法正常授權,
而最終,我采用了單用戶多OpenId的解決方案,每次用戶通過用戶名/密碼登錄時,產生一個OpenId保存在Redis里,并且設定過期時間,這樣多個終端登錄就會有多個OpenId與之對應,不再會存在一個OpenId失效所有終端驗證都失效的情況,
關注公眾號Java技術堆疊回復"面試"獲取我整理的2020最全面試題及答案,
推薦去我的博客閱讀更多:
1.Java JVM、集合、多執行緒、新特性系列教程
2.Spring MVC、Spring Boot、Spring Cloud 系列教程
3.Maven、Git、Eclipse、Intellij IDEA 系列工具教程
4.Java、后端、架構、阿里巴巴等大廠最新面試題
覺得不錯,別忘了點贊+轉發哦!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/158662.html
標籤:Java
上一篇:maven依賴沖突以及解決方法
