不管是什麼公司,只要產品數量大於一個,那麼單點登入勢必是繞不過去的一個問題。作為前端程式設計師,我們對其雖然接觸不多,但適當的瞭解還是必要的。本文就來談談單點登入相關的問題。
前置知識
瞭解 SSO,最好具備以下知識。當然,如果不是特別熟,也不影響閱讀。
- cookie及session
- 瀏覽器同源策略及跨域
- 瞭解登入系統的構成
什麼是 SSO 與 CAS?
SSO
SSO 是英文 Single Sign On 的縮寫,翻譯過來就是單點登入。顧名思義,它把兩個及以上個產品中的使用者登入邏輯抽離出來,達到只輸入一次使用者名稱密碼,就能同時登入多個產品的效果。
打個比方,SSO 和我們去迪士尼玩時購買的通票很像。
我們只要買一次通票,就可以玩所有遊樂場內的設施,而不需要在雲霄飛車或者摩天輪那裡重新買一次票。在這裡,買票就相當於登入認證,遊樂場就相當於使用一套 SSO 的公司,各種遊樂設施就相當於公司的各個產品。
使用 SSO 的優點很明顯:
- 提升使用者體驗。
- 避免重複開發
- 提升安全係數
假如你是我廠運維,發現了一個安全隱患需要緊急修復。你肯定無法忍受給茫茫多的產品後端都發一封郵件,責令修復吧?萬一漏了一個呢?
綜合看來,SSO 不僅是有用的,而且是必要的。
CAS
SSO 僅僅是一種架構,一種設計,而 CAS 則是實現 SSO 的一種手段。兩者是抽象與具體的關係。當然,除了 CAS 之外,實現 SSO 還有其他手段,比如簡單的 cookie。
CAS (Central Authentication Service)中心授權服務,本身是一個開源協議,分為 1.0 版本和 2.0 版本。1.0 稱為基礎模式,2.0稱為代理模式,適用於存在非 Web 應用之間的單點登入。本文只涉及 CAS 1.0,下文中將詳細介紹。
SSO 的演進與分類
下面詳述一下各種場景下的 SSO,它們之間是逐步升級,逐步複雜化的關係。
1.同域 SSO
如圖,同域 SSO 是最簡單的一種情況。
此時,兩個產品都是在一個域名下,單點登入是很自然的選擇。我們來捋一捋步驟,搞清楚這裡的步驟是理解後文的基礎,千萬不要跳過。
- 使用者訪問產品 a,向 後臺伺服器傳送登入請求。
- 登入認證成功,伺服器把使用者的登入資訊寫入 session。
- 伺服器為該使用者生成一個 cookie,並加入到 response header 中,隨著請求返回而寫入瀏覽器。該 cookie 的域設定為 dxy.cn。
- 下一次,當使用者訪問同域名的產品 b 時,由於 a 和 b 在同一域名下,也是 dxy.cn,瀏覽器會自動帶上之前的 cookie。此時後臺伺服器就可以通過該 cookie 來驗證登入狀態了。
實際上,這種場景就是最簡單最傳統的登入操作。雖然我們把產品 a 和 b 人為分開了,但由於它們在同域上,就算看成是同一產品的不同類目也未嘗不可。我們沒有設定獨立的 SSO 伺服器,因為業務後臺伺服器本身就足以承擔 SSO 的職能。
2.同父域 SSO
同父域 SSO 是同域 SSO 的簡單升級,唯一的不同在於,伺服器在返回 cookie 的時候,要把cookie 的 domain 設定為其父域。
比如兩個產品的地址分別為 a.dxy.cn 和 b.dxy.cn,那麼 cookie 的域設定為 dxy.cn 即可。在訪問 a 和 b 時,這個 cookie 都能傳送到伺服器,本質上和同域 SSO 沒有區別。
3.跨域 SSO
可以看到,在上面兩種情況下,我們都沒有專門設定 SSO 伺服器。但是當兩個產品不同域時,cookie 無法共享,所以我們必須設定獨立的 SSO 伺服器了。這個時候,我們就是通過標準的 CAS 方案來實現 SSO 的。下面我們就來詳細介紹一下:
詳解CAS
術語:
- Client:使用者。
- Server:中心伺服器,也是 SSO 中負責單點登入的伺服器。
- Service:需要使用單點登入的各個服務,相當於上文中的產品 a/b。
介面:
- /login:登入介面,用於登入到中心伺服器。
- /logout:登出介面,用於從中心伺服器登出。
- /validate:用於驗證使用者是否登入中心伺服器。
- /serviceValidate:用於讓各個 service 驗證使用者是否登入中心伺服器。
票據
- TGT:Ticket Grangting Ticket
TGT 是 CAS 為使用者簽發的登入票據,擁有了 TGT,使用者就可以證明自己在 CAS 成功登入過。TGT 封裝了 Cookie 值以及此 Cookie 值對應的使用者資訊。當 HTTP 請求到來時,CAS 以此 Cookie 值(TGC)為 key 查詢快取中有無 TGT ,如果有的話,則相信使用者已登入過。
- TGC:Ticket Granting Cookie
- ST:Service Ticket
票據之間的關係如下圖。注意,PGTIOU, PGT, PT 是 CAS 2.0 中的內容,感興趣的同學可以自行了解。
詳細步驟
看到這裡,是不是又有點暈了?沒關係,下面我們藉助一個簡單的場景,再來仔細捋一捋用 CAS 實現 SSO 的詳細步驟,順便加深理解之前提出的概念。
開始!
- 使用者訪問產品 a,域名是 www.a.cn。
- 由於使用者沒有攜帶在 a 伺服器上登入的 a cookie,所以 a 伺服器返回 http 重定向,重定向的 url 是 SSO 伺服器的地址,同時 url 的 query 中通過引數指明登入成功後,回跳到 a 頁面。重定向的url 形如 sso.dxy.cn/login?service=https%3A%2F%2Fwww.a.cn。
- 由於使用者沒有攜帶在 SSO 伺服器上登入的 TGC(看上面,票據之一),所以 SSO 伺服器判斷使用者未登入,給使用者顯示統一登入介面。使用者在 SSO 的頁面上進行登入操作。
- 登入成功後,SSO 伺服器構建使用者在 SSO 登入的 TGT(又一個票據),同時返回一個 http 重定向。這裡注意:
- 重定向地址為之前寫在 query 裡的 a 頁面。
- 重定向地址的 query 中包含 sso 伺服器派發的 ST。
- 重定向的 http response 中包含寫 cookie 的 header。這個 cookie 代表使用者在 SSO 中的登入狀態,它的值就是 TGC。
如圖所示,至此,整個登入流程結束。之後當使用者訪問 a 或者 b 後,直接會攜帶 a cookie/b cookie,就不用再向 SSO 確認了。
實際開發時,可以根據 CAS 增加更多的判斷邏輯,比如,在收到CAS Server簽發的ST後,如果 ST 被 hacker 竊取,並且 client 本身沒來得及去驗證 ST,被 hacker 搶先一步驗證 ST,怎麼解決。此時就可以在申請 ST 時新增額外驗證因子(如ip、sessionId等)。