谈谈SSO单点登录的设计实现
談談SSO單點登錄的設計實現
本篇將會講講單點登錄的具體實現。
實現思路
其實單點登錄在我們生活中很常見,比如學校的網站,有很多個系統,迎新系統,教務系統,網課系統。我們往往只需要登錄一次就能在各個系統中被認定為登錄狀態。
這是怎么實現的?我們需要一個認證中心,一如學校網站也有一個統一認證中心,也就是我們的SSO的Server端。在每個系統也就是Client端,我們只要判斷已經在這個認證中心中登錄,那我們就會被設置為登錄狀態。
再來就是最后一個問題了,我們判斷在認證中心登錄后,怎么在其他系統中也登錄?
這個問題其實就是單點登錄中最麻煩的問題了,也就是如何傳播我們的登錄狀態。
我們可以分為兩個情況Cookie共享傳播狀態,url參數傳播狀態。
Cookie共享傳播狀態
第一種情況:我們的認證中心和其他系統是在一個域名下的,認證中心為父域名(jwxt.com),其他系統是子域名(yx.jwxt.com),或者是同一IP不同端口的情況,我們的服務端通過cookie去判斷是否登錄。
在這種情況下我們只要在認證中心登錄成功的時候設置Cookie,當然設置Cookie的時候也要注意設置好你的Cookie參數。
要注意設置的參數是domin,path。這兩個參數值決定了Cookie的作用域。domin要設置為父域名(.jwxt.com)。當然還要注意一個SameSite參數,不能設置為None。(如果為None,你在baidu.com登錄,在example.com網站如果你點擊了 https://baidu.com/delete鏈接,會帶著你在baidu.com的Cookie訪問。)
設置完Cookie,子域名的系統也有了Cookie,自然就會被服務端判斷為登錄狀態。
簡而言之,就是利用Cookie共享來實現登錄狀態的傳播。
url參數傳播狀態
第二種我們的認證中心和其他系統不在一個域名下的,或者是不同IP的情況。
為了安全瀏覽器限制cookie跨域,也就是說第一種方法就不管用了。
這種情況可以通過傳播參數來實現,也就是在認證中心登錄后帶著 登錄憑證(token) 重定向到對應的Client頁面,然后我們的前端就可以用js獲取到url中的token進行存儲(設置到Cookie或者localstorage等方式),之后我們的服務端只需要通過這個token就可以判斷為登錄狀態了。
當然,為了安全我們往往不會直接傳遞憑證,而是傳遞一個校驗碼ticket,然后前端發送ticket到服務端校驗ticket,校驗成功,就進行登錄,設置Cookie或者存儲token。
流程
接下來我們梳理一下流程,一下Client為需要單點登錄的系統,Server為統一認證中心。
Cookie共享傳播狀態
- 用戶在Client1,如果沒有登錄,跳轉到Server,判斷在Server是否登錄,如果判斷沒有登錄,要求登錄,登錄成功后設置Cookie,跳轉Client
- Client1登錄成功
如果之后在Client2頁面,由于共享Cookie,當然也是登錄狀態。
url參數傳播狀態
- 用戶在Client1,判斷沒有登錄,跳轉到Server,判斷在Server是否登錄,如果沒有登錄,要求登錄,登錄成功后設置Cookie,帶著ticket跳轉Client。
- 到了Client1,前端通過參數獲取到ticket,發送到服務端,服務端校驗ticket獲取登錄id,設置Cookie進行登錄。
之后在Client2頁面
- 用戶在Client2,判斷沒有登錄,跳轉到Server,判斷在Server是否登錄,這時候判斷為登錄,帶著ticket(或者token)跳轉Client。
- 到了Client2,前端通過參數獲取到ticket,發送到服務端,服務端校驗ticket獲取登錄id,設置Cookie進行登錄。
如果不使用ticket校驗就直接存儲傳播過來的登錄憑證即可,當然如果你不存儲到Cookie,記得在請求后端服務的時候帶上token。
ticket校驗
再說說ticket校驗
ticket校驗根據情況也可以分為兩種,一種情況是Server和Client的后端共用的同一個Redis或者Redis集群,可以直接向Redis請求校驗。如果后端用的Redis不同,可以發送http請求到Server端在Server端校驗。
到此,單點登錄就完成了。
當然在以上描述中的Cookie你也可以不使用,使用Cookie主要是方便,在請求后端時會自動發送。你只需要存儲到localstorage/sessionstorage等地方,請求后端的時候記得get然后帶上即可。
總結
以上是生活随笔為你收集整理的谈谈SSO单点登录的设计实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 互联网那些技术 | 扒一扒互联网Mark
- 下一篇: 二叉树理论基础