前言:
是時候了解一下SSO相關的知識了,本篇主要是概念篇,發現網上兩篇不錯的文章,簡單整合了一下,原文鏈接:
https://www.cnblogs.com/Java3y/p/10877465.html
https://www.cnblogs.com/EzrealLiu/p/5559255.html
1、什么是SSO?
SSO( Single Sign-On ),中文意即單點登錄,單點登錄是一種控制多個相關但彼此獨立的系統的訪問權限,擁有這一權限的用戶可以使用單一的ID和密碼訪問某個或多個系統從而避免使用不同的用戶名或密碼,或者通過某種配置無縫地登錄每個系統。
SSO的一種較為通俗的定義是:SSO是在多個應用系統中,用戶只需要登錄一次就可以訪問所有相互信任的應用系統。它包括可以將這次主要的登錄映射到其他應用中用於同一個用戶的登錄的機制。它是目前比較流行的企業業務整合的解決方案之一。
術語比較繞,簡單概括:一次登錄,全部訪問。
單點登錄包含三個核心元素,即:用戶、系統、驗證中心。
以前我們的系統都是單系統,所有的功能都是在同一個系統上完成的。

后來,我們為了合理利用資源和降低耦合性,於是把單系統拆分成多個子系統。

從單系統到拆分成多個子系統,用戶登陸發生了什么變化呢?
以前登陸:用戶 > 系統
現在登陸:用戶 > 認證中心 > 系統

認證中心幫我們解決所有系統共享登陸。
2、SSO示例
阿里系的淘寶和天貓,很明顯地我們可以知道這是兩個系統,但是你在使用的時候,登錄了天貓,淘寶也會自動登錄。

不上多圖片了,可自行嘗試,淘寶的登陸網址為:login.taobao.com,我們在這個網站上登陸成功后,之后再訪問 i.taobao.com 、trade.taobao.com 、www.tmall.com 等子系統將不再需要重新登錄。

淘寶天貓的這個示例已經很明顯的展現了 SSO 的作用,一次登陸,全部訪問。
3、SSO要解決的問題(多系統登錄的問題與解決)
3.1 Session不共享問題
單系統登錄功能主要是用 Session 保存用戶信息來實現的,但我們清楚的是:多系統即可能有多個 Tomcat,而 Session 是依賴當前系統的 Tomcat,所以系統A 的 Session 和系統B 的 Session 是不共享的。

不共享會發生什么?A系統登陸的用戶,無法在B系統上直接使用。
解決系統之間的 Session 不共享問題有以下幾種方案:
- Tomcat集群Session全局復制(集群內每個tomcat的session完全同步)【會影響集群的性能呢,不建議】
- 根據請求的IP進行Hash映射到對應的機器上(這就相當於請求的IP一直會訪問同一個服務器)【如果服務器宕機了,會丟失了一大部分Session的數據,不建議】
- 把Session數據放在Redis中(使用Redis模擬Session)【建議】
-- 比如上篇提到的spring-session框架:https://www.cnblogs.com/niceyoo/p/11258392.html
我們可以將登錄功能單獨抽取出來,做成一個子系統。

SSO(登錄系統)的邏輯如下:
- SSO系統生成一個token,並將用戶信息存到Redis中,並設置過期時間
- 其他系統請求SSO系統進行登錄,得到SSO返回的token,寫到Cookie中
- 每次請求時,Cookie都會帶上,攔截器得到token,判斷是否已經登錄
至此,其實我們會發現其實就兩個變化:
- 將登陸功能抽取為一個系統(SSO),其他系統請求SSO進行登錄
- 本來將用戶信息存到Session,現在將用戶信息存到Redis
3.2 Cookie跨域問題
上面我們解決了Session不能共享的問題,但其實還有另一個問題。Cookie是不能跨域的
比如說,我們請求 https://www.google.com/ 時,瀏覽器會自動把google.com的Cookie帶過去給google的服務器,而不會把 https://www.baidu.com/ 的Cookie帶過去給google的服務器。
這就意味着,由於域名不同,用戶向系統A登錄后,系統A返回給瀏覽器的Cookie,用戶再請求系統B的時候不會將系統A的Cookie帶過去。
針對Cookie存在跨域問題,有幾種解決方案:
- 服務端將Cookie寫到客戶端后,客戶端對Cookie進行解析,將Token解析出來,此后請求都把這個Token帶上就行了
- 多個域名共享Cookie,在寫到客戶端的時候設置Cookie的domain。
- 將Token保存在SessionStroage中(不依賴Cookie就沒有跨域的問題了)
到這里,我們已經可以實現單點登錄了。
4、CAS原理
說到單點登錄,就肯定會見到這個名詞:CAS (Central Authentication Service),下面說說CAS是怎么搞的。
如果已經將登錄單獨抽取成系統出來,我們還能這樣玩。現在我們有兩個系統,分別是www.java3y.com和www.java4y.com,一個SSO www.sso.com

首先,用戶想要訪問系統A www.java3y.com 受限的資源(比如說購物車功能,購物車功能需要登錄后才能訪問),系統A www.java3y.com 發現用戶並沒有登錄,於是重定向到 SSO 認證中心,並將自己的地址作為參數。請求的地址如下:
www.sso.com?service=www.java3y.com
SSO 認證中心發現用戶未登錄,將用戶引導至登錄頁面,用戶進行輸入用戶名和密碼進行登錄,用戶與認證中心建立全局會話(生成一份 Token,寫到 Cookie 中,保存在瀏覽器上)

隨后,認證中心重定向回系統A,並把 Token 攜帶過去給系統A,重定向的地址如下:
www.java3y.com?token=xxxxxxx
接着,系統A去 SSO 認證中心驗證這個 Token 是否正確,如果正確,則系統A和用戶建立局部會話(創建Session)。到此,系統A和用戶已經是登錄狀態了。

此時,用戶想要訪問系統B www.java4y.com 受限的資源(比如說訂單功能,訂單功能需要登錄后才能訪問),系統B www.java4y.com 發現用戶並沒有登錄,於是重定向到 SSO 認證中心,並將自己的地址作為參數。請求的地址如下:
www.sso.com?service=www.java4y.com
注意,因為之前用戶與認證中心 www.sso.com 已經建立了全局會話(當時已經把 Cookie 保存到瀏覽器上了),所以這次系統B重定向到認證中心 www.sso.com 是可以帶上 Cookie 的。
認證中心根據帶過來的 Cookie 發現已經與用戶建立了全局會話了,認證中心重定向回系統B,並把 Token 攜帶過去給系統B,重定向的地址如下:
www.java4y.com?token=xxxxxxx
接着,系統B去 SSO 認證中心驗證這個 Token 是否正確,如果正確,則系統B和用戶建立局部會話(創建Session)。到此,系統B和用戶已經是登錄狀態了。

看到這里,其實SSO認證中心就類似一個中轉站。
5、本篇小結
SSO 這一理念到目前為止已經非常成熟,關於它的各種設計、設置都可以定制一套標准了。然而由於 SSO 與用戶有強關聯,所以很多設計在最初時往往會把 SSO 設計成一個用戶管理系統,而使得 SSO 與業務耦合,隨着業務的不斷變化和演進,底層數據結構、接口不斷的復雜化,又反過來使得上層服務的架構設計變得尷尬。
若做更進一層的抽象和划分,SSO只需負責登錄這單一功能即可,設計上滿足單一職責原則。
加上幾乎所有網站的登錄都大同小異(可能登錄界面會變幻無常)且不與業務有過多牽連,這又使得SSO與業務完全分離,無論將來業務怎樣演進,產品如何迭代,SSO作為底層應用可以以不變應萬變。
為什么要有SSO? 即SSO在解決什么問題?
隨着業務的不斷擴大,必然會對很多服務進行拆分,比如會做 SOA 服務,會使用 Dubbo 做微服務,或者簡單的小型分布式等,總之,拆分后的子系統必然存在着 session 同步等問題,目前 SSO 解決方案,目前比較流行的方案。
轉載了一篇<我們為何需要單點登錄系統>,可以圍觀一下。
下篇我們將通過一個國產框架 xxl-sso 了解一下單點登錄整個流程。