多站點(diǎn)單點(diǎn)登錄實(shí)現(xiàn)方案
今天寫(xiě)一篇關(guān)于多域名下單點(diǎn)登錄的實(shí)現(xiàn)。
有這么個(gè)場(chǎng)景,公司下有多個(gè)不同域名的站點(diǎn),我們期望用戶在任意一個(gè)站點(diǎn)下登錄后,在打開(kāi)另外幾個(gè)站點(diǎn)時(shí),也是已經(jīng)登錄的狀態(tài),這么一過(guò)程就是單點(diǎn)登錄。
因?yàn)槎鄠€(gè)站點(diǎn)都是用的同一套用戶體系,所以單點(diǎn)登錄可以免去用戶重復(fù)登錄,讓用戶在站點(diǎn)切換的時(shí)候更加流暢,甚至是無(wú)感知。
單點(diǎn)登錄所要實(shí)現(xiàn)的就是,某一站點(diǎn)登錄后,將其登錄態(tài)會(huì)同步到其他另外幾個(gè)站點(diǎn)。
我們分兩部分,先說(shuō)單個(gè)站點(diǎn)的登錄流程,再說(shuō)同步登錄態(tài)的流程。
登錄相關(guān)架構(gòu)
服務(wù)端采用? nodejs?,緩存采用?redis?。用戶登錄憑證采用基于? session?的?cookies?維系,采用?cookie?作為登錄憑證是目前比較主流的方式。session?信息用?redis?承載,從數(shù)據(jù)層面上看,?redis?中存儲(chǔ)?session?對(duì)象的?key?便是?cookie?中的?valuekey是由?UUID?生成的唯一標(biāo)識(shí)為了保證? session?與?cookie?保持對(duì)應(yīng),?session?對(duì)象創(chuàng)建與修改都會(huì)觸發(fā)服務(wù)端往瀏覽器寫(xiě)入?cookie
登錄流程
我們先看單個(gè)站點(diǎn)的登錄流程
用戶首次打開(kāi)站點(diǎn),服務(wù)端生成? session?對(duì)象,此時(shí)?session?中沒(méi)有用戶信息,同時(shí)服務(wù)端往瀏覽器寫(xiě)入?cookie用戶觸發(fā)登錄操作 服務(wù)端校驗(yàn)參數(shù)處理登錄邏輯后,生成用戶信息,將用戶信息寫(xiě)入? session?對(duì)象,更新緩存?redis我們來(lái)畫(huà)個(gè)圖,如下

同步登錄態(tài)
一個(gè)站點(diǎn)完成登錄后,接下來(lái)就是如何讓其他站點(diǎn)也擁有登錄態(tài)。既然登錄態(tài)是由?cookie?和?session?決定的,而?cookie?又是由?session?寫(xiě)入的,那么也就是說(shuō),只要把?session?同步到其它站點(diǎn),其它站點(diǎn)只要獲取到?session?后,就可以在該域名創(chuàng)建或更新 ?cookie?,這樣一來(lái),兩個(gè)不同域名下的站點(diǎn)就擁有相同的登錄信息了。
因此,同步登錄態(tài)其實(shí)就是,如何同步?session?的問(wèn)題。
而我們的?session?是采用?redis?作為載體,那么其他站點(diǎn)只要能獲取到?redis?中存儲(chǔ)的用戶信息,不就可以創(chuàng)建自己的?session?對(duì)象了么?
沒(méi)錯(cuò)!如何同步?session?的問(wèn)題,就變成了如何讓其他站點(diǎn)從?redis?中獲取用戶信息,也就是如何讓其他站點(diǎn)知道存儲(chǔ)該用戶信息的?redis key
到了這一步,我們需要解決的問(wèn)題就很明顯啦:如何在不同站點(diǎn)間傳輸用戶憑證。
為便于描述,我們假設(shè)有兩個(gè)站點(diǎn),分別為A站點(diǎn)和B站點(diǎn)。因?yàn)锳、B站點(diǎn)的域名不同,基于同源策略,?cookie?是沒(méi)法共享的,所以我們采取主動(dòng)請(qǐng)求的方式,將用戶唯一憑證通過(guò)接口傳過(guò)去。大致流程如下
A站點(diǎn)完成登錄邏輯后,將用戶憑證返回到瀏覽器,為了安全性,在傳輸憑證前,對(duì)憑證進(jìn)行加密,可采用? AES?或者?RSAA站點(diǎn)的客戶端獲取到憑證后,調(diào)用B站點(diǎn)提供的同步登錄態(tài)接口,將憑證傳過(guò)去 B站點(diǎn)的服務(wù)端獲取到憑證,解密,查詢(xún)緩存中的用戶信息,創(chuàng)建? session?對(duì)象,寫(xiě)入B站點(diǎn)域名下的?cookie?信息B站點(diǎn)的登錄態(tài)同步完成。
基于上圖,我們完善同步的時(shí)序圖

同步登錄態(tài)的場(chǎng)景
上面描述的是當(dāng)用戶首次登錄時(shí)的同步流程,還需要考慮其他場(chǎng)景,比如,B站點(diǎn)獲得的登錄態(tài)失效了,這時(shí)候訪問(wèn)B站點(diǎn)頁(yè)面,就需要在一次前往A站點(diǎn)同步登錄態(tài)。
B站點(diǎn)上的頁(yè)面分為兩種,一種是需要登錄態(tài)才可以訪問(wèn)的,一種是不需要登錄態(tài)就可以訪問(wèn)的。
第一種情況下,需要重定向到A站點(diǎn),可為啥要繞回去A站點(diǎn)呢?因?yàn)榇藭r(shí)我們也不知道A站點(diǎn)的登錄態(tài)是否也失效了,所以需要回到A站點(diǎn)判斷A站點(diǎn)當(dāng)前的登錄態(tài),若A站點(diǎn)登錄態(tài)也失效了,那么就去登陸頁(yè)進(jìn)行重新登錄,若A站點(diǎn)是有登陸態(tài)的,那么只要在做一次同步登錄態(tài)的操作即可。
第二種情況,雖然B頁(yè)面不需要登錄態(tài)就可以查看,但是企業(yè)網(wǎng)站往往會(huì)在頁(yè)面的head部分標(biāo)記用戶的登錄態(tài),所以為了讓這部分的顯示正常,我們?cè)诋?dāng)前頁(yè)面異步的去更新登錄態(tài)即可。
我們還是來(lái)畫(huà)圖,清晰一些,如下

若有其他場(chǎng)景,處理的邏輯與這個(gè)類(lèi)似,本質(zhì)無(wú)非就是在獲取一次憑證,重新更新站點(diǎn)緩存。
跨域請(qǐng)求
因?yàn)橐贏站點(diǎn)請(qǐng)求B域名下的接口,所以會(huì)有跨域問(wèn)題,跨域問(wèn)題常用的解決方式有如下幾種
JSONP?很常見(jiàn)很通用的一種方式Image?利用?Image src?可以繞過(guò)同源策略,所以通過(guò)構(gòu)建一個(gè)?Image?發(fā)送給請(qǐng)求也是可行的,同時(shí)服務(wù)端也不需要做太多修改。CORS?老的瀏覽器就沒(méi)法支持,需要在服務(wù)端設(shè)置?Access-Control-Allow-Origin,允許任何域或指定的域發(fā)起的請(qǐng)求都可以獲取當(dāng)前服務(wù)器的數(shù)據(jù)。
小結(jié)
文章主要是以方案描述為主,就不放上詳細(xì)的代碼了,有了具體方案,代碼的實(shí)現(xiàn)就不難啦。
多站點(diǎn)單點(diǎn)登錄肯定還有其他優(yōu)秀的解決方案,歡迎小伙伴們對(duì)話框留言或加我微信一起交流探討呀~
?? 看完三件事
如果你覺(jué)得這篇內(nèi)容對(duì)你挺有啟發(fā),我想邀請(qǐng)你幫我三個(gè)小忙:
點(diǎn)個(gè)「在看」,讓更多的人也能看到這篇內(nèi)容(喜歡不點(diǎn)在看,都是耍流氓 -_-)
關(guān)注我的官網(wǎng)?https://muyiy.cn,讓我們成為長(zhǎng)期關(guān)系
關(guān)注公眾號(hào)「高級(jí)前端進(jìn)階」,公眾號(hào)后臺(tái)回復(fù)「面試題」 送你高級(jí)前端面試題,回復(fù)「加群」加入面試互助交流群
