NET 單點登錄原理


簡介

單點登錄是在多個應用系統中,用戶只需要登錄一次就可以訪問所有相互信任的應用系統的保護資源,若用戶在某個應用系統中進行注銷登錄,所有的應用系統都不能再直接訪問保護資源,像一些知名的大型網站,如:淘寶與天貓、新浪微博與新浪博客等都用到了這個技術。

原理

  1. 單點登錄

    1. 有一個獨立的認證中心,只有認證中心才能接受用戶的用戶名和密碼等信息進行認證,其他系統不提供登錄入口,只接受認證中心的間接授權。間接授權通過令牌實現,當用戶提供的用戶名和密碼通過認證中心認證后,認證中心會創建授權令牌,在接下來的跳轉過程中,授權令牌作為參數發送給各個子系統,子系統拿到令牌即得到了授權,然后創建局部會話。
    2. 示例:
      單點登錄的原理
      下面對上圖進行解釋:
      1. 當用戶還沒進行用戶登錄的時候

        1. 用戶去訪問系統1的保護資源 ,系統1檢測到用戶還沒登錄,跳轉至SSO認證中心,SSO認證中心也發現用戶沒有登錄,就跳轉到用戶至認證中心的登錄頁面
        2. 用戶在登錄頁面提交用戶相應信息后,認證中心會校驗用戶信息,如果用戶信息正確的話認證中心就會創建與該用戶的全局會話(全局會話過期的時候,用戶就需要重新登錄了。全局會話中存的信息可能有令牌,用戶信息,及該在各個系統的一些情況),同時創建授權令牌,然后進行下一步,否則認證中心給出提示(用戶信息有誤),待用戶再次點擊登錄的時候,再一次進行校驗用戶信息
        3. 認證中心帶着令牌跳轉到用戶最初請求的地址(系統1),系統1拿到令牌后去SSO認證中心校驗令牌是否有效,SSO認證中心校驗令牌,若該令牌有效則進行下一步
        4. 注冊系統1,然后系統1使用該令牌創建和用戶的局部會話(若局部會話過期,跳轉至SSO認證中心,SSO認證中心發現用戶已經登錄,然后執行第3步),返回受保護資源
      2. 用戶已經通過認證中心的認證后
        用戶訪問系統2的保護資源,系統2發現用戶未登錄,跳轉至SSO認證中心,SSO認證中心發現用戶已經登錄,就會帶着令牌跳轉回系統2,系統2拿到令牌后去SSO認證中心校驗令牌是否有效,SSO認證中心返回有效,注冊系統2,系統2使用該令牌創建與用戶的局部會話,返回受保護資源。

      3. 如果系統1的局部會話存在的話,當用戶去訪問系統1的保護資源時,就直接返回保護資源,不需要去認證中心驗證了

    局部會話存在,全局會話一定存在;全局會話存在,局部會話不一定存在;全局會話銷毀,局部會話必須銷毀
    如果在校驗令牌過程中發現客戶端令牌和服務器端令牌不一致或者令牌過期的話,則用戶之前的登錄就過期了,用戶需要重新登錄

  2. 單點注銷

    1. 在一個子系統中注銷,全局會話也會被注銷,所有子系統的會話都會被注銷
    2. 示例:
      單點注銷原理
      用戶向系統1發出注銷請求,系統1根據用戶與系統1建立的會話id從會話中拿到令牌,向SSO認證中心發起注銷請求,認證中心校驗令牌有效,會銷毀全局會話,同時取出此令牌注冊的系統地址,認證中心向所有注冊系統發出注銷請求,各系統收到注銷請求后銷毀局部會話,認證中心引導用戶跳轉值登錄頁面。
  3. 整體陳述

    1. 單點登錄涉及SSO認證中心與多個子系統,子系統與SSO認證中心需要通信(交換令牌、校驗令牌及發起注銷請求等),子系統中包含SSO的客戶端,SSO認證中心是服務端
    2. 認證中心與客戶端通信可通過 httpClient、web service、rpc、restful api(url是其中一種) 等實現
    3. 客戶端與服務器端的功能
      1. 客戶端:
        1. 攔截子系統未登錄用戶請求,跳轉至sso認證中心
        2. 接收並存儲sso認證中心發送的令牌
        3. 與服務器端通信,校驗令牌的有效性
        4. 建立局部會話
        5. 攔截用戶注銷請求,向sso認證中心發送注銷請求
        6. 接收sso認證中心發出的注銷請求,銷毀局部會話
      2. 服務器端:
        1. 驗證用戶的登錄信息
        2. 創建全局會話
        3. 創建授權令牌
        4. 與客戶端通信發送令牌
        5. 校驗客戶端令牌有效性
        6. 系統注冊
        7. 接收客戶端注銷請求,注銷所有會話

 

大致思路是:

訪問業務系統時,由自定義的[Authorize]進行攔截

獲取到Token設置到請求頭進行HttpPost到認證系統提供的/api/token/Authentication接口

響應給業務系統如果是成功則繼續訪問,如果是失敗則401或者跳轉到登錄頁。

具體步驟:

  1. 認證中心登錄成功后,請求登錄中心接口獲得token
  2. 攜帶token逐個跳轉到業務系統的中轉頁面。
  3. 跳轉完成后,返回到認證中心登錄頁面進行引導。

在 B/S 系統中,登錄功能通常都是基於 Cookie 來實現的。當用戶登錄成功后,一般會將登錄狀態記錄到 Session 中,或者是給用戶簽發一個 Token,無論哪一種方式,都需要在客戶端保存一些信息(Session ID 或 Token ),並要求客戶端在之后的每次請求中攜帶它們。在這樣的場景下,使用 Cookie 無疑是最方便的,因此我們一般都會將 Session 的 ID 或 Token 保存到 Cookie 中,當服務端收到請求后,通過驗證 Cookie 中的信息來判斷用戶是否登錄 。

單點登錄(Single Sign On, SSO)是指在同一帳號平台下的多個應用系統中,用戶只需登錄一次,即可訪問所有相互信任的應用系統。舉例來說,百度貼吧和百度地圖是百度公司旗下的兩個不同的應用系統,如果用戶在百度貼吧登錄過之后,當他訪問百度地圖時無需再次登錄,那么就說明百度貼吧和百度地圖之間實現了單點登錄。

單點登錄的本質就是在多個應用系統中共享登錄狀態。如果用戶的登錄狀態是記錄在 Session 中的,要實現共享登錄狀態,就要先共享 Session,比如可以將 Session 序列化到 Redis 中,讓多個應用系統共享同一個 Redis,直接讀取 Redis 來獲取 Session。當然僅此是不夠的,因為不同的應用系統有着不同的域名,盡管 Session 共享了,但是由於 Session ID 是往往保存在瀏覽器 Cookie 中的,因此存在作用域的限制,無法跨域名傳遞,也就是說當用戶在 app1.com 中登錄后,Session ID 僅在瀏覽器訪問 app1.com 時才會自動在請求頭中攜帶,而當瀏覽器訪問 app2.com 時,Session ID 是不會被帶過去的。實現單點登錄的關鍵在於,如何讓 Session ID(或 Token)在多個域中共享。

在將具體實現之前,我們先來聊一聊 Cookie 的作用域。

Cookie 的作用域由 domain 屬性和 path 屬性共同決定。domain 屬性的有效值為當前域或其父域的域名/IP地址,在 Tomcat 中,domain 屬性默認為當前域的域名/IP地址。path 屬性的有效值是以“/”開頭的路徑,在 Tomcat 中,path 屬性默認為當前 Web 應用的上下文路徑。

如果將 Cookie 的 domain 屬性設置為當前域的父域,那么就認為它是父域 Cookie。Cookie 有一個特點,即父域中的 Cookie 被子域所共享,換言之,子域會自動繼承父域中的Cookie。

利用 Cookie 的這個特點,不難想到,將 Session ID(或 Token)保存到父域中不就行了。沒錯,我們只需要將 Cookie 的 domain 屬性設置為父域的域名(主域名),同時將 Cookie 的 path 屬性設置為根路徑,這樣所有的子域應用就都可以訪問到這個 Cookie 了。不過這要求應用系統的域名需建立在一個共同的主域名之下,如 tieba.baidu.com 和 map.baidu.com,它們都建立在 baidu.com 這個主域名之下,那么它們就可以通過這種方式來實現單點登錄。

總結:此種實現方式比較簡單,但不支持跨主域名。

實現方式二:LocalStorage 跨域

前面,我們說實現單點登錄的關鍵在於,如何讓 Session ID(或 Token)在多個域中共享。

父域 Cookie 確實是一種不錯的解決方案,但是不支持跨域。那么有沒有什么奇淫技巧能夠讓 Cookie 跨域傳遞呢?

很遺憾,瀏覽器對 Cookie 的跨域限制越來越嚴格。Chrome 瀏覽器還給 Cookie 新增了一個 SameSite 屬性,此舉幾乎禁止了一切跨域請求的 Cookie 傳遞(超鏈接除外),並且只有當使用 HTTPs 協議時,才有可能被允許在 AJAX 跨域請求中接受服務器傳來的 Cookie。

不過,在前后端分離的情況下,完全可以不使用 Cookie,我們可以選擇將 Session ID (或 Token )保存到瀏覽器的 LocalStorage 中,讓前端在每次向后端發送請求時,主動將 LocalStorage 的數據傳遞給服務端。這些都是由前端來控制的,后端需要做的僅僅是在用戶登錄成功后,將 Session ID (或 Token )放在響應體中傳遞給前端。

在這樣的場景下,單點登錄完全可以在前端實現。前端拿到 Session ID (或 Token )后,除了將它寫入自己的 LocalStorage 中之外,還可以通過特殊手段將它寫入多個其他域下的 LocalStorage 中。

實現方式三:登錄后給其他系統發請求 種下cookie

當用戶登錄其中的任何一個站點時,我們需要針對其他每個站點在瀏覽器端設置cookie信息。

如果用戶在onmpw1站點進行登錄,登錄成功授權以后,瀏覽器將會存儲一份兒onmpw1站點的cookie信息。同時,為了可以登錄onmpw2和onmpw3,我們需要在設置onmpw1的cookie的同事也對onmpw2和onmpw3進行cookie設置。因此在對onmpw1進行響應之前,我們需要先跳轉到onmpw2和onmpw3站點去設置cookie信息。

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

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

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

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

五、onmpw1收到提交的驗證信息,開始驗證這些信息。如果驗證成功,則標記該用戶已經登錄。然后會創建帶有登錄用戶信息的cookie,並將其加入響應信息中。

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

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

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

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

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

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

這樣,單點登錄就已經設置成功了。在本例中,按照上述步驟,登錄onmpw1以后,onmpw2和onmpw3就可以同時實現登錄了。

如何退出登錄

既然我們已經實現了單點登錄,但是我們還得考慮退出的問題。既然是同時登錄的,那總不能在退出的時候一個一個的退出吧!所以說我們還要設置單點退出。

要想實現單點退出,在本例中,我們需要做的是當在一個站點退出的時候,其他兩個站點的cookie同樣也需要在瀏覽器中清除。這樣才可以實現單點退出。

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

對於這種情況,不管是單點登錄也好,還是單點退出。都存在一個問題,在本例中我們只是有三個站點。如果說我們整個系統有10個20個或者更多站點,那像我們這樣來回的重定向會很影響效率。

實現方式四:認證中心

我們可以部署一個認證中心,認證中心就是一個專門負責處理登錄請求的獨立的 Web 服務。

用戶統一在認證中心進行登錄,登錄成功后,認證中心記錄用戶的登錄狀態,並將 Token 寫入 Cookie。(注意這個 Cookie 是認證中心的,應用系統是訪問不到的。)

應用系統檢查當前請求有沒有 Token,如果沒有,說明用戶在當前系統中尚未登錄,那么就將頁面跳轉至認證中心。由於這個操作會將認證中心的 Cookie 自動帶過去,因此,認證中心能夠根據 Cookie 知道用戶是否已經登錄過了。如果認證中心發現用戶尚未登錄,則返回登錄頁面,等待用戶登錄,如果發現用戶已經登錄過了,就不會讓用戶再次登錄了,而是會跳轉回目標 URL ,並在跳轉前生成一個 Token,拼接在目標 URL 的后面,回傳給目標應用系統。

應用系統拿到 Token 之后,還需要向認證中心確認下 Token 的合法性,防止用戶偽造。確認無誤后,應用系統記錄用戶的登錄狀態,並將 Token 寫入 Cookie,然后給本次訪問放行。(注意這個 Cookie 是當前應用系統的,其他應用系統是訪問不到的。)當用戶再次訪問當前應用系統時,就會自動帶上這個 Token,應用系統驗證 Token 發現用戶已登錄,於是就不會有認證中心什么事了。

總結:此種實現方式相對復雜,支持跨域,擴展性好,是單點登錄的標准做法。

現在我們有兩個系統,分別是www.java3y.com和www.java4y.com,一個SSOwww.sso.com

首先,用戶想要訪問系統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和用戶已經是登錄狀態了。

此時,用戶想要訪問系統Bwww.java4y.com受限的資源(比如說訂單功能,訂單功能需要登錄后才能訪問),系統Bwww.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和用戶已經是登錄狀態了。

 

傳統session和cookie 以及jwt sso 參考

https://blog.csdn.net/weixin_41888813/article/details/102657309

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM