單點登陸

咱們用大樓,保安,請求進入者,小紙條,來訪者登記表這個場景比喻,整理了cookie(http://www.javashuo.com/article/p-tlmdohfp-ko.html)和session(http://www.javashuo.com/article/p-fgljnokt-s.html)。假設咱們如今遇到一張這樣的狀況,就是G集團很大,它有不少幢大樓,按照以前的方式,來訪者進入#1號大樓要校驗登記,進入#2號大樓也要校驗登陸...以此類推,它須要在每一幢大樓裏面都校驗,而且登記一次,這樣手續很繁瑣,並且效率很低。那有沒有一種方法,讓我只要校驗登記一次,就能夠在整個集團內的全部大樓裏暢行無阻呢?這就涉及到單點登陸了。java

單點登陸

英文Single Sign On, 簡單來講,就是在一個多系統的環境中,用戶在其中一個系統登陸後,在進入其餘系統的時候,不須要再次進行登陸,而是直接擁有登錄狀態。這種多系統,主要是爲了合理利用資源,下降耦合度,把原系統拆分紅多個子系統而成的。好比,淘寶和天貓,它們就實現了單點登陸功能,用戶在淘寶登陸後,進入天貓頁面,就直接有了登陸態。數據庫

HTTP回顧

衆所周知,HTTP是無狀態的寫一,這意味着服務端沒法確認用戶的信息,因而有了cookie。這樣,用戶在後續的請求中都帶上session_id,從而讓服務端識別當前會話,以及當前會話的用戶。固然,除了session_id以外,還可使用token來區分。也就是在登陸時,生成一個token,這個token能夠保存在數據庫中或者緩存中,對應到用戶信息(好比以token爲key, uid爲value),而後把token寫入cookie,以後的每次請求都帶上cookie,而後經過cookie中的token來獲取用戶信息。跨域

固然,cookie中的一些敏感信息要注意加密,使用的時候,傳到服務端去解密。瀏覽器

登陸意味着寫入,那麼註銷登陸意味着刪除,記住我 意味着關閉瀏覽器後,在一段時間內打開瀏覽器,仍然保持登陸狀態。緩存

多系統登陸的問題及解決方案

3.1 Session(登記表)不共享問題

A系統的session存在A系統中,B系統的session存在B系統中,不互相共享,這樣就不能共用同一個session_id了。安全

有如下幾種方案:服務器

3.1.1 會話複製: 能夠作成session集羣,而後集羣內部徹底同步,這樣集羣內部每個節點都擁有集羣全部節點的數據。可是這樣會影響集羣的性能,不建議使用。相似於全部大樓都存全部大樓的登記表。cookie

3.1.2 會話保持:能夠根據IP作Hash映射的負載均衡,這樣同一個IP會一直訪問同一臺服務器。這樣有一個問題,就是對服務器的穩定性要求高,若是出現宕(dàng)機,會有一大部分請求沒法命中,遷移到其餘機器。相似於一個總的登記中心,有不少個窗口,每一個窗口都有去全部大樓的班車,可是每一個窗口只處理一部分訪問請求。session

3.1.3 會話共享: 將Session數據放到緩存中,如Redis,使用Redis模擬Session. 核心思想就是負載均衡

3.1.3.1 讓客戶端訪問同一個sessionId
3.1.3.2 讓全部域名對應的服務器訪問的Session的數據的位置必須一致

相似於全集團共用同一個登記中心,每一個大樓均可以直接去讀寫這個登記中心的數據。

咱們能夠把登陸功能單獨抽取出來,作成一個SSO子系統。其餘的子系統登陸時,請求SSO進行登陸,若是已經登陸,則直接放行,若是沒有登陸,則執行登陸,SSO系統生成一個session_id或者token, 存入Redis, 返回時將session_id或者token放入cookie中,之後其餘系統訪問時帶上cookie,攔截器獲得session_id/token,判斷是否存在,是否過時,進而判斷是否已登陸。

3.2 Cookie(小紙條)跨域問題

咱們知道,Cookie中經過Domain域和Path路徑來控制Cookie的使用範圍。當瀏覽器訪問A網站/系統時,會把A網站/域名的Cookie帶過去,訪問B時,也只會把B的Cookie帶過去,因爲域名不一樣,不會把其餘域的Cookie帶過去。

分幾種狀況

3.2.1 屬於同一個頂級域名下的多個子域名,能夠在設置Cookie時,講Domain設爲頂級域名,這樣在訪問頂級域名下的任何子域名時,瀏覽器都會帶上該Cookie的鍵值對,就能共用同一個Cookie了。

3.2.2 跨多個頂級域名。這種狀況有點複雜。


3.2.2.1 因爲站點A(www.A.com)不能讀取到由站點P(www.P.com)建立的加密ticket,因此當用戶訪問A站點上須要登陸才能訪問的資源時,A站點會首先查看是否有A-ticket。 若是有且沒有過時,則直接使用。

3.2.2.2 若是沒有或者已過時,則證實用戶沒有在A站點登陸過或者已經失效,不過並不保證用戶沒有在B站點登陸,(重複一下,既然是單點登陸,固然不管你在A,B任意一個站點登陸過,另一個站點都要能夠訪問),請求會被重定向到P站點的驗證頁面.

3.2.2.3 校驗P站點的Cookie, 若是存在且沒有過時,則直接重定向回站點A,同時將驗證信息Session_id/P-ticket返回給站點A。

3.2.2.4 若是P站點沒有Cookie或者已失效,則跳轉到Login登陸頁面,輸入登陸信息,登陸頁面完成登陸後,生成一個P站點的Session_id/P-ticket,寫入一個加密cookie,而後重定向到A站點的登陸處理頁,並把加密的用戶信息做爲參數傳遞給這個頁面,這個頁面接收登陸頁的用戶信息,解密後也要寫一個cookie,也就是A-ticket,從此用戶再次訪問A站點上須要登陸權限才能訪問的資源時,只須要檢查這個A-cookie是否存在就能夠了。

3.2.2.5 當用戶訪問B站點時,會重複上面的過程,監測到沒有B-ticket,就會重定向到P站點的驗證頁面,去檢查P-ticket,若是沒有,就登陸,有則返回B的登陸處理頁面寫B-ticket。

3.2.2.6 註銷的時候須要刪除P-ticket和A-ticket。

3.2.2.7 怎麼刪除cookie: 簡單的說實際上是建立一個和你要刪除的cookie同名的cookie,並把cookie的expire設爲當前時間以前的某個時間,不過在跨子域的刪除cookie時有一點要注意:必需要把cookie的域設置爲父域.

3.2.2.8 爲了保證各個環節的傳輸的安全性,最好使用https鏈接。

到這裏,咱們已經能夠實現單點登陸了。

3.3 CAS原理

說到單點登陸,就確定會見到這個名詞:CAS (Central Authentication Service),下面說說CAS是怎麼搞的。

若是已經將登陸單獨抽取成系統出來,如今咱們有兩個系統,分別是www.java3y.com和www.java4y.com,還有一個SSO認證中心: www.sso.com

 

3.3.1 用戶想要訪問系統Awww.java3y.com受限的資源(好比說購物車功能,購物車功能須要登陸後才能訪問),系統Awww.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和用戶已是登陸狀態了。

3.3.2 此時,用戶想要訪問系統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認證中心就相似一個中轉站

相關文章
相關標籤/搜索