SSO單點登入三種情況的實現方式詳解

onmpw.com發表於2016-05-23

單點登入(SSO——Single Sign On)對於我們來說已經不陌生了。對於大型系統來說使用單點登入可以減少使用者很多的麻煩。就拿百度來說吧,百度下面有很多的子系統——百度經驗、百度知道、百度文庫等等,如果我們使用這些系統的時候,每一個系統都需要我們輸入使用者名稱和密碼登入一次的話,我相信使用者體驗肯定會直線下降。當然,對於個人部落格這類系統來說根本就用不上單點登入了。

假如,我們的系統很龐大,但是就是這一個系統,並沒有什麼子系統。這時我們也不需要單點登入。我們需要的是搭建叢集環境,這裡雖說只有一個系統,但是多臺主機負載均衡的話就涉及到session共享的問題了。Session共享問題較之於SSO來說將比較容易解決了。

好,我們不管不需要單點登入的系統了。題目中已經標明瞭SSO單點登入的三種情況,下面我們分別來介紹這三種情況。

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

我們知道,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資訊。

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

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

一、使用者向www.onmpw1.com(以下簡稱onmpw1)請求一個需要驗證的頁面。

[狀態: 瀏覽器還沒有驗證的cookie資訊]

二、瀏覽器向onmpw1傳送請求(該請求沒有cookie資訊,因為它還沒有儲存所屬域為onmpw1.com的cookie資訊)。

[狀態: 瀏覽器還沒有驗證的cookie資訊]

三、onmpw1發現在請求中沒有帶cookie資訊,所以它將請求重定向到登入頁面

[狀態: 瀏覽器還沒有驗證的cookie資訊]

四、使用者提交了登入所需驗證的資訊並且點選登入按鈕,瀏覽器傳送一個post請求到onmpw1。

[狀態: 瀏覽器還沒有驗證的cookie資訊]

五、onmpw1收到提交的驗證資訊,開始驗證這些資訊。如果驗證成功,則標記該使用者已經登入。然後會建立帶有登入使用者資訊的cookie,並將其加入響應資訊中。

[狀態: 瀏覽器還沒有驗證的cookie資訊]

六、onmpw1暫時還不去響應瀏覽器的請求。這時它將會向瀏覽器傳送重定向到www.onmpw2.com(以下簡稱onmpw2)的命令,並且還帶有在onmpw2站點需要返回的url地址,該地址為最初onmpw1中的。因為cookie資訊已經在響應資訊中,所以這個cookie也被髮送給瀏覽器了。

[狀態: 瀏覽器還沒有驗證的cookie資訊]

七、瀏覽器接收道帶有驗證的cookie資訊和重定向到onmpw2的命令的響應資訊以後,將cookie資訊的域設定為onmpw2儲存到本地,並且想onmpw2傳送請求。這個請求中會帶有剛才的cookie資訊。

[狀態:瀏覽器中已經有所屬域為onmpw2的cookie資訊]

八、onmpw2立刻會重定向到需要返回的url地址,並且通過讀取瀏覽器傳送的cookie資訊,獲取到onmpw1的cookie。並將這cookie也一同傳送給瀏覽器。

[狀態:瀏覽器中已經有所屬域為onmpw2的cookie資訊]

九、瀏覽器在接受到這些資訊以後,會將所屬域為onmpw1的cookie儲存在本地。並且再次向onmpw1傳送一個帶有cookie資訊的請求。

[狀態:瀏覽器中已經有所屬域為onmpw2和onmpw1的cookie資訊]

十、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,然後將請求的頁面傳送給瀏覽器輸出。

本文比較長,顯得有些囉嗦。但是總是希望過程能給大家講清楚。希望本文對大家有所幫助。

相關文章