單點登陸(SSO)

背景

在企業發展初期,企業使用的系統不多,一般一個或者兩個,每一個系統都有本身的登陸模塊,運營人員天天用本身的帳號登陸,很方便。php

但隨着企業的發展,用到的系統隨之增多,運營人員在操做不一樣的系統時,須要屢次登陸,並且每一個系統的帳號都不同,這對於運營人員html

來講,很不方便。因而,就想到是否是能夠在一個系統登陸,其餘系統就不用登陸了呢?這就是單點登陸要解決的問題。web

單點登陸英文全稱Single Sign On,簡稱就是SSO。它的解釋是:在多個應用系統中,只須要登陸一次,就能夠訪問其餘相互信任的應用系統。跨域

如圖所示,圖中有4個系統,分別是Application一、Application二、Application三、和SSO。Application一、Application二、Application3沒有登陸模塊,而SSO只有登陸模塊,沒有其餘的業務模塊,當Application一、Application二、Application3須要登陸時,將跳到SSO系統,SSO系統完成登陸,其餘的應用系統也就隨之登陸了。這徹底符合咱們對單點登陸(SSO)的定義。瀏覽器

技術實現

在說單點登陸(SSO)的技術實現以前,咱們先說一說普通的登陸認證機制。緩存



如上圖所示,咱們在瀏覽器(Browser)中訪問一個應用,這個應用須要登陸,咱們填寫完用戶名和密碼後,完成登陸認證。這時,咱們在這個用戶的session中標記登陸狀態爲yes(已登陸),同時在瀏覽器(Browser)中寫入Cookie,這個Cookie是這個用戶的惟一標識。下次咱們再訪問這個應用的時候,請求中會帶上這個Cookie,服務端會根據這個Cookie找到對應的session,經過session來判斷這個用戶是否登陸。若是不作特殊配置,這個Cookie的名字叫作jsessionid,值在服務端(server)是惟一的。安全

同域下的單點登陸

一個企業通常狀況下只有一個域名,經過二級域名區分不一樣的系統。好比咱們有個域名叫作:a.com,同時有兩個業務系統分別爲:app1.a.com和app2.a.com。咱們要作單點登陸(SSO),須要一個登陸系統,叫作:sso.a.com。服務器

咱們只要在sso.a.com登陸,app1.a.com和app2.a.com就也登陸了。經過上面的登錄認證機制,咱們能夠知道,在sso.a.com中登陸了,實際上是在sso.a.com的服務端的session中記錄了登陸狀態,同時在瀏覽器端(Browser)的sso.a.com下寫入了Cookie。那麼咱們怎麼才能讓app1.a.com和app2.a.com登陸呢?這裏有兩個問題:cookie

  • Cookie是不能跨域的,咱們Cookie的domain屬性是sso.a.com,在給app1.a.com和app2.a.com發送請求是帶不上的。
  • sso、app1和app2是不一樣的應用,它們的session存在本身的應用內,是不共享的。

那麼咱們如何解決這兩個問題呢?針對第一個問題,sso登陸之後,能夠將Cookie的域設置爲頂域,即.a.com,這樣全部子域的系統均可以訪問到頂域的Cookie。咱們在設置Cookie時,只能設置頂域和本身的域,不能設置其餘的域。好比:咱們不能在本身的系統中給baidu.com的域設置Cookie。session

Cookie的問題解決了,咱們再來看看session的問題。咱們在sso系統登陸了,這時再訪問app1,Cookie也帶到了app1的服務端(Server),app1的服務端怎麼找到這個Cookie對應的Session呢?這裏就要把3個系統的Session共享,如圖所示。共享Session的解決方案有不少,例如:Spring-Session。這樣第2個問題也解決了。

同域下的單點登陸就實現了,但這還不是真正的單點登陸。

不一樣域下的單點登陸

同域下的單點登陸是巧用了Cookie頂域的特性。若是是不一樣域呢?不一樣域之間Cookie是不共享的,怎麼辦?

這裏咱們就要說一說CAS流程了,這個流程是單點登陸的標準流程。


上圖是CAS官網上的標準流程,具體流程以下:

  1. 用戶訪問app系統,app系統是須要登陸的,但用戶如今沒有登陸。
  2. 跳轉到CAS server,即SSO登陸系統,之後圖中的CAS Server咱們統一叫作SSO系統。 SSO系統也沒有登陸,彈出用戶登陸頁。
  3. 用戶填寫用戶名、密碼,SSO系統進行認證後,將登陸狀態寫入SSO的session,瀏覽器(Browser)中寫入SSO域下的Cookie。
  4. SSO系統登陸完成後會生成一個ST(Service Ticket),而後跳轉到app系統,同時將ST做爲參數傳遞給app系統。
  5. app系統拿到ST後,從後臺向SSO發送請求,驗證ST是否有效。
  6. 驗證經過後,app系統將登陸狀態寫入session並設置app域下的Cookie。

至此,跨域單點登陸就完成了。之後咱們再訪問app系統時,app就是登陸的。接下來,咱們再看看訪問app2系統時的流程。

  1. 用戶訪問app2系統,app2系統沒有登陸,跳轉到SSO。
  2. 因爲SSO已經登陸了,不須要從新登陸認證。
  3. SSO生成ST,瀏覽器跳轉到app2系統,並將ST做爲參數傳遞給app2。
  4. app2拿到ST,後臺訪問SSO,驗證ST是否有效。
  5. 驗證成功後,app2將登陸狀態寫入session,並在app2域下寫入Cookie。

這樣,app2系統不須要走登陸流程,就已是登陸了。SSO,app和app2在不一樣的域,它們之間的session不共享也是沒問題的。

有的同窗問我,SSO系統登陸後,跳回原業務系統時,帶了個參數ST,業務系統還要拿ST再次訪問SSO進行驗證,以爲這個步驟有點多餘。他想SSO登陸認證經過後,經過回調地址將用戶信息返回給原業務系統,原業務系統直接設置登陸狀態,這樣流程簡單,也完成了登陸,不是很好嗎?

其實這樣問題時很嚴重的,若是我在SSO沒有登陸,而是直接在瀏覽器中敲入回調的地址,並帶上僞造的用戶信息,是否是業務系統也認爲登陸了呢?這是很可怕的。

總結

單點登陸(SSO)的全部流程都介紹完了,原理你們都清楚了。總結一下單點登陸要作的事情:

  • 單點登陸(SSO系統)是保障各業務系統的用戶資源的安全 。
  • 各個業務系統得到的信息是,這個用戶能不能訪問個人資源。
  • 單點登陸,資源都在各個業務系統這邊,不在SSO那一方。 用戶在給SSO服務器提供了用戶名密碼後,做爲業務系統並不知道這件事。 SSO隨便給業務系統一個ST,那麼業務系統是不能肯定這個ST是用戶僞造的,仍是真的有效,因此要拿着這個ST去SSO服務器再問一下,這個用戶給個人ST是否有效,是有效的我才能讓這個用戶訪問。

原文:https://www.jianshu.com/p/75edcc05acfd

 

在同一個域名下的不一樣站點是如何進行驗證的

咱們知道,PHP表單驗證是徹底依賴於Cookie的。所以說,若是兩個站點能夠共享相同的驗證Cookie,這將很容易實現使用同一個用戶登陸多個站點。

按照HTTP協議規定,兩個站點是能夠共享Cookie的。前提是這兩個站點是在同一個域名下面(或者是二級域名也可)。這種狀況是屬於同域下的Cookie。瀏覽器會將Cookie以及該Cookie所屬的域存在本地。當你對該域下的任何子站點進行訪問的時候,瀏覽器都會將這些Cookie發送給站點系統。

假設咱們有兩個站點

www.onmpw.com/site1
www.onmpw.com/site2

這兩個站點共享同一個主機地址,而且兩者在同一域名下。加入你剛剛登陸了www.onmpw.com/site1,你的瀏覽器會有一個來自www.onmpw.com/site1的身份鑑證的cookie。當你點擊site1下的任何的子頁面的時候,這些cookie都會發送給site1。這是很容易理解的。一樣的,當你請求www.onmpw.com/site2的時候,對於site2下面的任何頁面這些cookie也一樣會隨着請求發送過去。爲何是這樣,由於在瀏覽器端存儲的cookie的域是www.onmpw.com。site1和site2兩個站點是同屬於該域的。因此對於該域下的cookie,兩個站點均可以獲得。

這種狀況,若是系統是PHP的話咱們根本不須要進行什麼特殊的處理。只須要按照正常的驗證方式進行驗證便可。由於兩者的sessionId是相同的,只要它們的session信息是保存在同一個地方便可。

同一個域可是不一樣的子域如何進行單點登陸

假如咱們的站點是按照下面的域名進行部署的

sub1.onmpw.com
sub2.onmpw.com

這兩個站點共享同一域onmpw.com。

默認狀況下,瀏覽器會發送cookie所屬的域對應的主機。也就是說,來自於sub1.onmpw.com的cookie默認所屬的域是.sub1.onmpw.com。所以,sub2.onmpw.com不會獲得任何的屬於sub1.onmpw.com的cookie信息。由於它們是在不一樣的主機上面,而且兩者的子域也是不一樣的。

這種狀況,若是咱們使用PHP來實現的話,能夠設置兩者的cookie信息在同一個域下。

第一 登陸sub1.onmpw.com系統

第二 登陸成功之後,設置cookie信息。這裏須要注意,咱們能夠將用戶名和密碼存到cookie中,可是在設置的時候必須將這cookie的所屬域設置爲頂級域 .onmpw.com。這裏可使用setcookie函數,該函數的第四個參數是用來設置cookie所述域的。

setcookie(‘username’,’onmpw’,null,’.onmpw.com’);
setcookie(‘password’,’pwd’,null,’.onmpw.com’);

第三 訪問sub2.onmpw.com系統,瀏覽器會將cookie中的信息username和password附帶在請求中一起發送到sub2.onmpw.com系統。這時該系統會先檢查session是否登陸,若是沒有登陸則驗證cookie中的username和password從而實現自動登陸。

第四 sub2.onmpw.com 登陸成功之後再寫session信息。之後的驗證就用本身的session信息驗證就能夠了。

固然,先登陸sub2.onmpw.com的方式也是相同的。通過上面的步驟就能夠實現不一樣二級域名的單點登陸了。

可是,這裏存在一個問題就是sub1系統退出之後,除了能夠清除自身的session信息和所屬域爲.onmpw.com的cookie的信息。它並不能清除sub2系統的session信息。那sub2仍然是登陸狀態。也就是說,這種方式雖然說能夠實現單點登陸,可是不能實現同時退出。緣由是,sub1和sub2雖然說經過setcookie函數的設置能夠共享cookie,可是兩者的sessionId是不一樣的,並且這個sessionId在瀏覽器中也是以cookie的形式存儲的,不過它所屬的域並非.onmpw.com。也就是說兩者的sessionId是不一樣的。

那如何解決這個問題呢?咱們知道,對於這種狀況,只要是兩個系統的sessionId相同就能夠解決這個問題了。也就是說存放sessionId的cookie所屬的域也是.onmpw.com。在PHP中,sessionId是在session_start()調用之後生成的。要想使sub1和sub2有共同的sessionId,那必須在session_start()以前設置sessionId所屬域。有兩種方式:

第一 使用php函數ini_set函數進行以下設置

ini_set('session.cookie_path', '/');
ini_set('session.cookie_domain', '.onmpw.com');
ini_set('session.cookie_lifetime', '0');

第二 直接修改php.ini 文件

session.cookie_path = /
session.cookie_domain = '.onmpw.com'
session.cookie_lifetime = 0

通過以上設置,sub1和sub2系統就會使用相同的session信息了。這樣既能夠實現單點登陸,也能夠實現同時退出。

不一樣域之間如何實現單點登陸

假設咱們須要在如下這些站之間實現單點登陸

www.onmpw1.com
www.onmpw2.com
www.onmpw3.com

對於這種狀況,咱們有兩種實現方式,其中咱們先來介紹實現比較簡單的方式。

方式一

爲了實現單點登陸,當用戶登陸其中的任何一個站點時,咱們須要針對其餘每一個站點在瀏覽器端設置cookie信息。

若是用戶在onmpw1站點進行登陸,登陸成功受權之後,瀏覽器將會存儲一份兒onmpw1站點的cookie信息。同時,爲了能夠登陸onmpw2和onmpw3,咱們須要在設置onmpw1的cookie的同事也對onmpw2和onmpw3進行cookie設置。所以在對onmpw1進行響應以前,咱們須要先跳轉到onmpw2和onmpw3站點去設置cookie信息。

 

下圖是對於兩個站點的單點登陸模型(三個的圖畫起來比較麻煩,爲了節省時間,就用兩個來表示,可是原理是相同的)

此種狀況的驗證步驟是這樣的:

1、用戶向www.onmpw1.com(如下簡稱onmpw1)請求一個須要驗證的頁面。

[狀態: 瀏覽器尚未驗證的cookie信息]

2、瀏覽器向onmpw1發送請求(該請求沒有cookie信息,由於它尚未存儲所屬域爲onmpw1.com的cookie信息)。

[狀態: 瀏覽器尚未驗證的cookie信息]

3、onmpw1發如今請求中沒有帶cookie信息,因此它將請求重定向到登陸頁面

[狀態: 瀏覽器尚未驗證的cookie信息]

4、用戶提交了登陸所需驗證的信息而且點擊登陸按鈕,瀏覽器發送一個post請求到onmpw1。

[狀態: 瀏覽器尚未驗證的cookie信息]

5、onmpw1收到提交的驗證信息,開始驗證這些信息。若是驗證成功,則標記該用戶已經登陸。而後會建立帶有登陸用戶信息的cookie,並將其加入響應信息中。

[狀態: 瀏覽器尚未驗證的cookie信息]

6、onmpw1暫時還不去響應瀏覽器的請求。這時它將會向瀏覽器發送重定向到www.onmpw2.com(如下簡稱onmpw2)的命令,而且還帶有在onmpw2站點須要返回的url地址,該地址爲最初onmpw1中的。由於cookie信息已經在響應信息中,因此這個cookie也被髮送給瀏覽器了。

[狀態: 瀏覽器尚未驗證的cookie信息]

7、瀏覽器接收道帶有驗證的cookie信息和重定向到onmpw2的命令的響應信息之後,將cookie信息的域設置爲onmpw2存儲到本地,而且想onmpw2發送請求。這個請求中會帶有剛纔的cookie信息。

[狀態:瀏覽器中已經有所屬域爲onmpw2的cookie信息]

8、onmpw2馬上會重定向到須要返回的url地址,而且經過讀取瀏覽器發送的cookie信息,獲取到onmpw1的cookie。並將這cookie也一同發送給瀏覽器。

[狀態:瀏覽器中已經有所屬域爲onmpw2的cookie信息]

9、瀏覽器在接受到這些信息之後,會將所屬域爲onmpw1的cookie存儲在本地。而且再次向onmpw1發送一個帶有cookie信息的請求。

[狀態:瀏覽器中已經有所屬域爲onmpw2和onmpw1的cookie信息]

10、onmpw1接收到驗證信息之後,知道驗證cookie已經設置成功。此時onmpw1會返回相應的請求界面,而再也不是登陸界面。

[狀態:瀏覽器中已經有所屬域爲onmpw2和onmpw1的cookie信息]

因此說,當用戶再次訪問onmpw2的時候,cookie信息已經存儲到瀏覽器中了。這時onmpw2會在cookie中讀取到登陸的用戶的信息,而後提供相應的界面給瀏覽器。

這樣,單點登陸就已經設置成功了。在本例中,按照上述步驟,登陸onmpw1之後,onmpw2和onmpw3就能夠同時實現登陸了。

如何退出登陸

既然咱們已經實現了單點登陸,可是咱們還得考慮退出的問題。既然是同時登陸的,那總不能在退出的時候一個一個的退出吧!因此說咱們還要設置單點退出。

要想實現單點退出,在本例中,咱們須要作的是當在一個站點退出的時候,其餘兩個站點的cookie一樣也須要在瀏覽器中清除。這樣才能夠實現單點退出。

這樣其實也很簡單,在理解了上述單點登陸的流程之後,單點退出只是按照上面的步驟將設置驗證cookie改爲從響應信息中移除cookie就能夠實現了。

對於這種狀況,無論是單點登陸也好,仍是單點退出。都存在一個問題,在本例中咱們只是有三個站點。若是說咱們整個系統有10個20個或者更多站點,那像咱們這樣來回的重定向會很影響效率。

方式二

接下來咱們來介紹另外一種方式。這種方式須要咱們藉助一個單獨的SSO服務,專門作驗證用。並且咱們還須要對於不一樣的站點的用戶要有一個統一的用戶數據。相對於前一種方式——瀏覽器須要存儲每一個站點的cookie——來講,這種方式瀏覽器只須要存儲SSO服務站點的cookie信息。將這個cookie信息用於其餘站點從而實現單點登陸。咱們暫且將這個SSO服務站點成爲www.SSOsite.com(如下簡稱SSOsite)。

在這種模型下,針對任何站點的請求都將會先重定向到SSOsite去驗證一個身份驗證cookie是否存在。若是存在,則驗證過的頁面將會發送給瀏覽器。不然用戶將會被重定向到登陸頁面。

爲了理解此種方式,如今假設咱們來運用這種模型實現如下兩個站點的單點登陸。

www.onmpw1.com(如下簡稱onmpw1)
www.onmpw2.com(如下簡稱onmpw2)

而且咱們還有一個專門用來進行驗證的服務站點www.SSOsite.com(如下簡稱SSOsite) 。

第一部分

實現流程

·用戶請求onmpw1的一個須要驗證的頁面

·onmpw1向瀏覽器發送重定向到SSOsite的命令。而且在地址中添加一個返回地址(ReturnUrl)參數query string,該參數的值就是最初向onmpw1請求的地址。

·SSOsite會在請求中檢查是否有身份驗證cookie,或者任何用戶token。沒有這些信息,則會再次重定向到onmpw1,在重定向到onmpw1中的請求中會帶有參數讓用戶登陸的url參數和最初的瀏覽器請求onmpw1的地址——ReturnUrl。

·onmpw1會檢測從SSOsite重定向來的請求的參數。這時onmpw1瞭解到該用戶須要登陸,所以onmpw1會重定向到登陸界面,而且通知瀏覽器該請求不用再重定向到SSOsite。

第二部分

·用戶提供了身份驗證信息而且點擊了登陸按鈕。如今不會再去重定向到SSOsite。這時,onmpw1調用SSOsite 中的web/WCF服務去檢查用戶提供的身份驗證信息。成功驗證,會將帶有token屬性的用戶對象返回給onmpw1。而這個token是每一次用戶登陸都會生成的。

·onmpw1標記用戶已經登陸成功,而後會生成一個URL地址,該地址會帶有用戶token,重定向到SSOsite。

·SSOsite檢查收到的URL地址,會在其中發現用戶token。經過該token能夠知道用戶已經成功登陸onmpw1了,因此SSOsite須要準備驗證的cookie信息。所以,它會使用token在緩存中取出用戶信息來生成cookie信息,並且還會在cookie中設置一些其餘的信息(例如過時時間等)。而後把cookie加入到響應信息中。最後重定向到最初的ReturnUrl地址。同時token仍是要被加在query string中帶過去的。

·瀏覽器獲得重定向到onmpw1的命令,而且從SSOsite中獲得cookie信息。所以瀏覽器將所屬域爲SSOsite的cookie保存在本地。而後帶着token去請求onmpw1。

·如今onmpw1看到用戶token在query string 參數中,而後會再次經過web/WCF服務去在SSOsite上驗證token。驗證成功之後會將最初剛開始請求的頁面發送給瀏覽器用於向用戶輸出。

第三部分

·用戶如今去請求onmpw2。

·onmpw2重定向到SSOsite,一樣設置ReturnUrl爲剛開始請求的onmpw2的頁面地址。

·瀏覽器接收到重定向的命令之後,由於本地存在SSOsite的cookie,因此會cookie加到請求中發送給SSOsite。

·SSOsite檢查接收到的請求中發現有cookie信息,首先會檢查該cookie信息是否過時,若是沒有過時,將會從cookie中提取出用戶token。而後帶着token重定向到最初的onmpw2中的地址。

·onmpw2發現請求中有用戶token,而後他會經過SSOsite的web/WCF服務驗證token的合法性。驗證成功之後,將最初瀏覽器請求onmpw2的頁面發送給瀏覽器用以向用戶輸出。

總結

哇哦,看起來有不少東西須要作。其實並無那麼複雜。

起初,瀏覽器沒有所屬域爲SSOsite的cookie信息。所以不管是點擊任何站點的須要驗證的界面都會跳轉到登陸頁(這個過程是由程序內部重定向到SSOsite來檢查是否存在cookie的)。一旦用戶登陸成功,所屬域爲SSOsite的,而且帶有登陸用戶信息的cookie會被瀏覽器存儲在本地。

而後,當用戶再次訪問須要驗證的頁面的時候,一樣請求會在被重定向到SSOsite,而且瀏覽器會帶上先前已經保存的cookie信息。SSOsite檢索cookie,從中提取出用戶token,並帶着這個token重定向到最初請求的站點頁面。而後該站點會經過web/WCF服務去驗證token的合法性。而後將相應的頁面發送給客戶端。

一旦用戶經過該單點登陸模型登陸到站點上,請求任何須要驗證的頁面都會內部重定向到SSOsite驗證cookie和提取用戶token,而後將請求的頁面發送給瀏覽器輸出。

原文:https://www.cnblogs.com/wxj-106/p/8097880.html

相關文章
相關標籤/搜索