跨域單點(diǎn)登錄實現(xiàn)
時間:2023-02-23 03:00:01 | 來源:建站知識
時間:2023-02-23 03:00:01 來源:建站知識
跨域單點(diǎn)登錄實現(xiàn):SSO英文全稱Single Sign On,單點(diǎn)登錄。當(dāng)我們搜索
單點(diǎn)登錄
的時候,會發(fā)現(xiàn)很多的文章,然而這些文章一般都是基于一種通用的場景描述,通常在各自的業(yè)務(wù)環(huán)境會更加復(fù)雜。在本篇文章,我將描述具體場景下實現(xiàn)單點(diǎn)登錄的方案。
SSO英文全稱Single Sign On,單點(diǎn)登錄。SSO是在多個應(yīng)用系統(tǒng)中,用戶只需要登錄一次就可以訪問所有相互信任的應(yīng)用系統(tǒng)。它包括可以將這次主要的登錄映射到其他應(yīng)用中用于同一個用戶的登錄的機(jī)制。它是目前比較流行的企業(yè)業(yè)務(wù)整合的解決方案之一。
背景
企業(yè)發(fā)展初期,一般一個域名站點(diǎn)便可承載獨(dú)立業(yè)務(wù)。但隨企業(yè)對于新業(yè)務(wù)的探索,便都會申請一個新的域名用于這部分新業(yè)務(wù)的功能承載,一方面是為了做區(qū)分,另一方面是滿足監(jiān)管的要求。并且需要在這種模式下打通原先站點(diǎn)的用戶體系。新的獨(dú)立域名主要有兩種:
- 原有站點(diǎn)是www.a.com,新獨(dú)立域名是new.a.com;
- 原有站點(diǎn)是www.a.com,新獨(dú)立域名是www.b.com;
對于第一種場景,一般我們采用共享
session
的方式就可以做到用戶在不同域名之間跳轉(zhuǎn)而無需重復(fù)登錄。具體實現(xiàn)主要是將
cookies
中關(guān)于用戶登錄態(tài)的
sessionid
的domain設(shè)置為
.a.com
。
這種場景較為簡單,實現(xiàn)上做好新老模式之間的切換即可。因為默認(rèn)情況下sessionId的domian是
www.a.com
,如果之前已經(jīng)訪問過www.a.com站點(diǎn),且登錄的時候未清除掉domian為
www.a.com
的sessionid,那么訪問
www.a.com
的站點(diǎn),瀏覽器會把兩個同名sessionId傳遞到服務(wù)端,由于是
key-value
的形式,服務(wù)端無法分辨哪個是新的,哪個是舊的,如果取了舊的,那么就無法獲取用戶此時登錄狀態(tài)。解決這個問題,只需要在設(shè)置sessionId的時候把原有domian為
www.a.com
的置為過期,或者用一個新的sessionId鍵即可。具體查看set-cookies介紹。
這種場景在我們的移動站點(diǎn)用的比較多。例如主站
http://www.a.com,移動站點(diǎn)為
http://m.a.com這種場景。
#設(shè)置domian為.a.com的sessionIdSet-Cookie: sessionId=a3fWa; Domain=.a.com; Secure; HttpOnly#將domian為www.a.com的sessionId置為過期Set-Cookie: sessionId=a3fWa; Domain=www.a.com; expires=Thu, 01 Jan 1970 00:00:00 GMT; Secure; HttpOnly
接下來我們主要描述第二種場景。對于這種場景,主要要求是用戶無感知,需要做到以下幾點(diǎn):
- a站點(diǎn)登錄之后往b站點(diǎn)同步登錄態(tài);
- 訪問b站點(diǎn)無需登錄頁面后,需要主動同步a站點(diǎn)登錄態(tài);
- 訪問b站點(diǎn)需要登錄頁面時,需要跳轉(zhuǎn)到a站點(diǎn)做登錄態(tài)同步;
流程一:a站點(diǎn)登錄之后往b站點(diǎn)同步登錄態(tài)
以上是主動同步登錄態(tài)的時序圖。圖示中的ticket主要存放在
redis
中,你也可以存放在其他的存儲媒介甚至應(yīng)用運(yùn)行內(nèi)存,但是需要注意的一點(diǎn)就是
ticket應(yīng)一次有效,用過之后需要清除掉。由于這里我們的b站點(diǎn)也在自己的受控范圍,并且redis的讀寫性能也相當(dāng)優(yōu)越,所以a和b連接并讀取了同個redis。如果b站點(diǎn)不在受控范圍內(nèi),可在b站點(diǎn)后臺發(fā)起一個請求到a站點(diǎn)詢問ticket的有效狀態(tài)。具體流程如下:
- 用戶訪問http://a.com的登錄頁;
- 輸入用戶名密碼登錄,http://a.com后臺校驗用戶,成功之后生成a站點(diǎn)的sesion并生成一個ticket放入redis中;
- 登錄頁面登錄成功之后,拿到ticket往http://b.com發(fā)送一個跨域請求(JSONP或者Image);
- b站點(diǎn)獲取到ticket之后,檢驗在redis是否存在,存在著設(shè)置b站點(diǎn)session并刪除ticket;
- 跨域請求返回之后繼續(xù)其他操作,如跳轉(zhuǎn)用戶中心,首頁等。
流程二:b站點(diǎn)無需登錄頁面主動同步a站點(diǎn)登錄態(tài)
由于a、b站點(diǎn)相互獨(dú)立,假設(shè)各自的session過期時間為半小時,如果a站點(diǎn)一直處于訪問狀態(tài),那么session會一直續(xù)命下去,但是b站點(diǎn)由于超過30分鐘沒有訪問,session狀態(tài)已經(jīng)過期,這時候訪問b站點(diǎn)就會有這個場景了。具體流程如下:
- 用戶訪問http://b.com無需登錄頁面;
- 如果當(dāng)前站點(diǎn)用戶未登錄,發(fā)起異步JSONP請求到http://a.com;
- 如果http://a.com未登錄,不做任何操作。如果已經(jīng)登錄,跟上個流程一樣,生成ticket信息;
- 拿到ticket之后,請求b站點(diǎn)同步登錄狀態(tài),b站點(diǎn)生成session;
- 同步成功之后主動重新刷新當(dāng)前頁面。
流程三:b站點(diǎn)需登錄頁面主動跳轉(zhuǎn)到a站點(diǎn)做登錄態(tài)同步
同流程二,這個場景的出現(xiàn)也是因為長時間未訪問登錄b站點(diǎn)導(dǎo)致,與流程二不同的是,這個場景是302直接跳轉(zhuǎn)同步頁面的方式,由后臺直接判斷,適合后臺直出頁面,如果是純靜態(tài)頁面請使用流程二,具體流程如下:
- 用戶訪問http://b.com需要登錄頁面,返回302跳轉(zhuǎn)到a站點(diǎn)的狀態(tài)同步頁面;
- a站點(diǎn)狀態(tài)同步頁面判斷站點(diǎn)登錄狀態(tài),未登錄狀態(tài)跳轉(zhuǎn)到a站點(diǎn)的登錄頁面,登錄流程同流程一,登錄成功之后跳轉(zhuǎn)b站點(diǎn)需登錄頁面;
- 已經(jīng)登錄狀態(tài)做JSONP登錄狀態(tài)同步到b站點(diǎn),b站點(diǎn)生成session;
- 同步b站點(diǎn)成功之后跳轉(zhuǎn)到http://b.com站點(diǎn)需要登錄頁面。
總結(jié)
以上流程主要在于實現(xiàn)SSO過程的針對各種場景的解決方案,根據(jù)通過發(fā)起方的不同又可分為兩類,主動同步和被動同步。主動同步是向認(rèn)證站點(diǎn)獲取ticket并同步自身登錄態(tài),被動同步是由認(rèn)證站點(diǎn)向當(dāng)前站點(diǎn)同步登錄態(tài)。
一般網(wǎng)上的資料會有一個專門用作認(rèn)證登錄的站點(diǎn),比如
http://a.com和
http://b.com站點(diǎn)都從
http://sso.a.com獲取認(rèn)證狀態(tài)。其實在本文中就是把a(bǔ)站點(diǎn)用作sso站點(diǎn)了,原理上是一致的。
為了這一套方案落地的時候,業(yè)務(wù)開發(fā)同事無需關(guān)注這部分實現(xiàn)細(xì)節(jié)并編寫相應(yīng)的同步代碼,我們把他寫入了整體框架里面,主要做了一下兩件事:
- 封裝前端登錄腳本(支持npm引用,直接webpack打包),登錄之后去做主動站點(diǎn)同步,業(yè)務(wù)同事在需要登錄的場景,直接調(diào)用方法并在回調(diào)函數(shù)做其他操作;
- 使用ejs或者pug等模板引擎,將流程二的同步過程放入通用模板,其他頁面在通用模板基礎(chǔ)上創(chuàng)建。
更多關(guān)于sso認(rèn)證方面的可以參考OAuth2的流程,這套流程用于不可信站點(diǎn)之間的認(rèn)證在安全方面會更加成熟些,也是目前微信采用的認(rèn)證流程。
原文鏈接:跨域單點(diǎn)登錄方案實現(xiàn)