單點登陸在如今的系統架構中普遍存在,他將多個子系統的認證體系打通,實現了一個入口多處使用,而在架構單點登陸時,也會遇到一些小問題,在不一樣的應用環境中能夠採用不一樣的單點登陸實現方案來知足需求。我將以我所遇到的應用環境以及在其中所經歷的各個階段與你們分享,如有不足,但願各位不吝賜教。html
共享Session可謂是實現單點登陸最直接、最簡單的方式。將用戶認證信息保存於Session中,即以Session內存儲的值爲用戶憑證,這在單個站點內使用是很正常也很容易實現的,而在用戶驗證、用戶信息管理與業務應用分離的場景下即會遇到單點登陸的問題,在應用體系簡單,子系統不多的狀況下,能夠考慮採用Session共享的方法來處理這個問題。java
這個架構我使用了基於Redis的Session共享方案。將Session存儲於Redis上,而後將整個系統的全局Cookie Domain設置於頂級域名上,這樣SessionID就能在各個子系統間共享。python
這個方案存在着嚴重的擴展性問題,首先,ASP.NET的Session存儲必須爲SessionStateItemCollection對象,而存儲的結構是通過序列化後通過加密存儲的。而且當用戶訪問應用時,他首先作的就是將存儲容器裏的全部內容所有取出,而且反序列化爲SessionStateItemCollection對象。這就決定了他具備如下約束:跨域
一、 Session中所涉及的類型必須是子系統中共同擁有的(即程序集、類型都須要一致),這致使Session的使用受到諸多限制;安全
二、 跨頂級域名的狀況徹底沒法處理;架構
這種單點登陸將用戶的身份標識信息簡化爲OpenId存放於客戶端,當用戶登陸某個子系統時,將OpenId傳送到服務端,服務端根據OpenId構造用戶驗證信息,多用於C/S與B/S相結合的系統,流程以下:app
由上圖能夠看到,這套單點登陸依賴於OpenId的傳遞,其驗證的基礎在於OpenId的存儲以及發送。加密
一、當用戶第一次登陸時,將用戶名密碼發送給驗證服務;spa
二、驗證服務將用戶標識OpenId返回到客戶端;視頻
三、客戶端進行存儲;
四、訪問子系統時,將OpenId發送到子系統;
五、子系統將OpenId轉發到驗證服務;
六、驗證服務將用戶認證信息返回給子系統;
七、子系統構建用戶驗證信息後將受權後的內容返回給客戶端。
這套單點登陸驗證機制的主要問題在於他基於C/S架構下將用戶的OpenId存儲於客戶端,在子系統之間發送OpenId,而B/S模式下要作到這一點就顯得較爲困難。爲了處理這個問題咱們將引出下一種方式,這種方式將解決B/S模式下的OpenId的存儲、傳遞問題。
咱們知道,Cookie的做用在於充當一個信息載體在Server端和Browser端進行信息傳遞,而Cookie通常是以域名爲分割的,例如a.xxx.com與b.xxx.com的Cookie是不能互相訪問的,可是子域名是能夠訪問上級域名的Cookie的。即a.xxx.com和b.xxx.com是能夠訪問xxx.com下的Cookie的,因而就能將頂級域名的Cookie做爲OpenId的載體。
驗證步驟和上第二個方法很是類似:
一、 在提供驗證服務的站點裏登陸;
二、 將OpenId寫入頂級域名Cookie裏;
三、 訪問子系統(Cookie裏帶有OpenId)
四、 子系統取出OpenId經過並向驗證服務發送OpenId
五、 返回用戶認證信息
六、 返回受權後的內容
在以上兩種方法中咱們均可以看到經過OpenId解耦了Session共享方案中的類型等問題,而且構造用戶驗證信息將更靈活,子系統間的驗證是相互獨立的,可是在第三種方案裏,咱們基於全部子系統都是同一個頂級域名的假設,而在實際生產環境裏有多個域名是很正常的事情,那麼就不得不考慮跨域問題究竟如何解決。
在多個頂級域名的狀況下,咱們將沒法讓各個子系統的OpenId共享。處理B/S環境下的跨域問題,咱們首先就應該想到JSONP的方案。
驗證步驟以下:
一、 用戶經過登陸子系統進行用戶登陸;
二、 用戶登陸子系統記錄了用戶的登陸狀態、OpenId等信息;
三、 用戶使用業務子系統;
四、 若用戶未登陸業務子系統則將用戶跳轉至用戶登陸子系統;
五、 用戶子系統經過JSONP接口將用戶OpenId傳給業務子系統;
六、 業務子系統經過OpenId調用驗證服務;
七、 驗證服務返回認證信息、業務子系統構造用戶登陸憑證;(此時用戶客戶端已經與子業務系統的驗證信息已經一一對應)
八、 將用戶登陸結果返回用戶登陸子系統,若成功登陸則將用戶跳轉回業務子系統;
九、 將受權後的內容返回客戶端;
通過以上步驟,跨域狀況下的單點登陸問題已經能夠獲得解決。而在整個開發過程初期,咱們採用用戶表中紀錄一個OpenId字段來保存用戶OpenId,而這個機制下很明顯存在一些安全性、擴展性問題。這個擴展性問題主要體如今一個方面:OpenId的安全性和用戶體驗的矛盾。
整個單點登陸的機制決定了OpenId是會出如今客戶端的,因此OpenId須要有過時機制,假如用戶在一個終端登陸的話能夠選擇在用戶每次登陸或者每次退出時刷新OpenId,而在多終端登陸的狀況下就會出現矛盾:當一個終端刷新了OpenId以後其餘終端將沒法正常受權。而最終,我採用了單用戶多OpenId的解決方案。每次用戶經過用戶名/密碼登陸時,產生一個OpenId保存在Redis裏,而且設定過時時間,這樣多個終端登陸就會有多個OpenId與之對應,再也不會存在一個OpenId失效全部終端驗證都失效的狀況。
通常說來,大型應用會把受權的邏輯與用戶信息的相關邏輯獨立成一個應用,稱爲用戶中心。用戶中心不處理業務邏輯,只是處理用戶信息的管理以及受權給第三方應用。第三方應用須要登陸的時候,則把用戶的登陸請求轉發給用戶中心進行處理,用戶處理完畢返回憑證,第三方應用驗證憑證,經過後就登陸用戶。
做者:ULiiAn·竹
連接:
https://www.cnblogs.com/UliiAn/p/3803042.html
-END-