談談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然後帶上即可。