學(xué)號(hào):17020110019? ? 姓名:高少魁
轉(zhuǎn)載自:https://mp.weixin.qq.com/s/wO11F4e0rJTMXWteVfAxzA
【嵌牛導(dǎo)讀】介紹了三種B/S系統(tǒng)中單點(diǎn)登錄的方式:父域cookie在旱、認(rèn)證中心、LocalStorage跨域。
【嵌牛鼻子】單點(diǎn)登錄? ? 共享登錄狀態(tài)? ? Session共享與多域名共享
【嵌牛正文】
一喧锦、前言
在 B/S 系統(tǒng)中夏伊,登錄功能通常都是基于 Cookie 來(lái)實(shí)現(xiàn)的睹栖。當(dāng)用戶登錄成功后敛瓷,一般會(huì)將登錄狀態(tài)記錄到 Session 中颜懊,或者是給用戶簽發(fā)一個(gè) Token河哑,無(wú)論哪一種方式避诽,都需要在客戶端保存一些信息(Session ID 或 Token ),并要求客戶端在之后的每次請(qǐng)求中攜帶它們璃谨。在這樣的場(chǎng)景下沙庐,使用 Cookie 無(wú)疑是最方便的,因此我們一般都會(huì)將 Session 的 ID 或 Token 保存到 Cookie 中佳吞,當(dāng)服務(wù)端收到請(qǐng)求后拱雏,通過(guò)驗(yàn)證 Cookie 中的信息來(lái)判斷用戶是否登錄 。
單點(diǎn)登錄(Single Sign On, SSO)是指在同一帳號(hào)平臺(tái)下的多個(gè)應(yīng)用系統(tǒng)中底扳,用戶只需登錄一次铸抑,即可訪問(wèn)所有相互信任的應(yīng)用系統(tǒng)。舉例來(lái)說(shuō)花盐,百度貼吧和百度地圖是百度公司旗下的兩個(gè)不同的應(yīng)用系統(tǒng)羡滑,如果用戶在百度貼吧登錄過(guò)之后,當(dāng)他訪問(wèn)百度地圖時(shí)無(wú)需再次登錄算芯,那么就說(shuō)明百度貼吧和百度地圖之間實(shí)現(xiàn)了單點(diǎn)登錄柒昏。
單點(diǎn)登錄的本質(zhì)就是在多個(gè)應(yīng)用系統(tǒng)中共享登錄狀態(tài)。如果用戶的登錄狀態(tài)是記錄在 Session 中的熙揍,要實(shí)現(xiàn)共享登錄狀態(tài)职祷,就要先共享 Session,比如可以將 Session 序列化到 Redis 中届囚,讓多個(gè)應(yīng)用系統(tǒng)共享同一個(gè) Redis有梆,直接讀取 Redis 來(lái)獲取 Session。
當(dāng)然僅此是不夠的意系,因?yàn)椴煌膽?yīng)用系統(tǒng)有著不同的域名泥耀,盡管 Session 共享了,但是由于 Session ID 是往往保存在瀏覽器 Cookie 中的蛔添,因此存在作用域的限制痰催,無(wú)法跨域名傳遞兜辞,也就是說(shuō)當(dāng)用戶在 app1.com 中登錄后,Session ID 僅在瀏覽器訪問(wèn) app1.com 時(shí)才會(huì)自動(dòng)在請(qǐng)求頭中攜帶夸溶,而當(dāng)瀏覽器訪問(wèn) app2.com 時(shí)逸吵,Session ID 是不會(huì)被帶過(guò)去的。實(shí)現(xiàn)單點(diǎn)登錄的關(guān)鍵在于缝裁,如何讓 Session ID(或 Token)在多個(gè)域中共享扫皱。
二、實(shí)現(xiàn)方式一:父域Cookie
在將具體實(shí)現(xiàn)之前捷绑,我們先來(lái)聊一聊 Cookie 的作用域韩脑。
Cookie 的作用域由 domain 屬性和 path 屬性共同決定。domain 屬性的有效值為當(dāng)前域或其父域的域名/IP地址粹污,在 Tomcat 中扰才,domain 屬性默認(rèn)為當(dāng)前域的域名/IP地址。path 屬性的有效值是以“/”開(kāi)頭的路徑厕怜,在 Tomcat 中衩匣,path 屬性默認(rèn)為當(dāng)前 Web 應(yīng)用的上下文路徑。
如果將 Cookie 的 domain 屬性設(shè)置為當(dāng)前域的父域粥航,那么就認(rèn)為它是父域 Cookie琅捏。Cookie 有一個(gè)特點(diǎn),即父域中的 Cookie 被子域所共享递雀,換言之柄延,子域會(huì)自動(dòng)繼承父域中的Cookie。
利用 Cookie 的這個(gè)特點(diǎn)缀程,不難想到搜吧,將 Session ID(或 Token)保存到父域中不就行了。沒(méi)錯(cuò)杨凑,我們只需要將 Cookie 的 domain 屬性設(shè)置為父域的域名(主域名)滤奈,同時(shí)將 Cookie 的 path 屬性設(shè)置為根路徑,這樣所有的子域應(yīng)用就都可以訪問(wèn)到這個(gè) Cookie 了撩满。不過(guò)這要求應(yīng)用系統(tǒng)的域名需建立在一個(gè)共同的主域名之下蜒程,如 tieba.baidu.com 和 map.baidu.com,它們都建立在 baidu.com 這個(gè)主域名之下伺帘,那么它們就可以通過(guò)這種方式來(lái)實(shí)現(xiàn)單點(diǎn)登錄昭躺。
總結(jié):此種實(shí)現(xiàn)方式比較簡(jiǎn)單,但不支持跨主域名伪嫁。
三领炫、實(shí)現(xiàn)方式二:認(rèn)證中心
我們可以部署一個(gè)認(rèn)證中心,認(rèn)證中心就是一個(gè)專門(mén)負(fù)責(zé)處理登錄請(qǐng)求的獨(dú)立的 Web 服務(wù)张咳。
用戶統(tǒng)一在認(rèn)證中心進(jìn)行登錄帝洪,登錄成功后针史,認(rèn)證中心記錄用戶的登錄狀態(tài),并將 Token 寫(xiě)入 Cookie碟狞。(注意這個(gè) Cookie 是認(rèn)證中心的,應(yīng)用系統(tǒng)是訪問(wèn)不到的婚陪。)
應(yīng)用系統(tǒng)檢查當(dāng)前請(qǐng)求有沒(méi)有 Token族沃,如果沒(méi)有,說(shuō)明用戶在當(dāng)前系統(tǒng)中尚未登錄泌参,那么就將頁(yè)面跳轉(zhuǎn)至認(rèn)證中心脆淹。由于這個(gè)操作會(huì)將認(rèn)證中心的 Cookie 自動(dòng)帶過(guò)去,因此沽一,認(rèn)證中心能夠根據(jù) Cookie 知道用戶是否已經(jīng)登錄過(guò)了盖溺。如果認(rèn)證中心發(fā)現(xiàn)用戶尚未登錄,則返回登錄頁(yè)面铣缠,等待用戶登錄烘嘱,如果發(fā)現(xiàn)用戶已經(jīng)登錄過(guò)了,就不會(huì)讓用戶再次登錄了蝗蛙,而是會(huì)跳轉(zhuǎn)回目標(biāo) URL 蝇庭,并在跳轉(zhuǎn)前生成一個(gè) Token,拼接在目標(biāo) URL 的后面捡硅,回傳給目標(biāo)應(yīng)用系統(tǒng)哮内。
應(yīng)用系統(tǒng)拿到 Token 之后,還需要向認(rèn)證中心確認(rèn)下 Token 的合法性壮韭,防止用戶偽造北发。確認(rèn)無(wú)誤后,應(yīng)用系統(tǒng)記錄用戶的登錄狀態(tài)喷屋,并將 Token 寫(xiě)入 Cookie琳拨,然后給本次訪問(wèn)放行。(注意這個(gè) Cookie 是當(dāng)前應(yīng)用系統(tǒng)的屯曹,其他應(yīng)用系統(tǒng)是訪問(wèn)不到的从绘。)當(dāng)用戶再次訪問(wèn)當(dāng)前應(yīng)用系統(tǒng)時(shí),就會(huì)自動(dòng)帶上這個(gè) Token是牢,應(yīng)用系統(tǒng)驗(yàn)證 Token 發(fā)現(xiàn)用戶已登錄僵井,于是就不會(huì)有認(rèn)證中心什么事了。
這里順便介紹兩款認(rèn)證中心的開(kāi)源實(shí)現(xiàn):
1驳棱、Apereo CAS 是一個(gè)企業(yè)級(jí)單點(diǎn)登錄系統(tǒng)批什,其中 CAS 的意思是”Central Authentication Service“。它最初是耶魯大學(xué)實(shí)驗(yàn)室的項(xiàng)目社搅,后來(lái)轉(zhuǎn)讓給了 JASIG 組織驻债,項(xiàng)目更名為 JASIG CAS乳规,后來(lái)該組織并入了Apereo 基金會(huì),項(xiàng)目也隨之更名為 Apereo CAS合呐。
2暮的、XXL-SSO 是一個(gè)簡(jiǎn)易的單點(diǎn)登錄系統(tǒng),由大眾點(diǎn)評(píng)工程師許雪里個(gè)人開(kāi)發(fā)淌实,代碼比較簡(jiǎn)單冻辩,沒(méi)有做安全控制,因而不推薦直接應(yīng)用在項(xiàng)目中拆祈,這里列出來(lái)僅供參考恨闪。
總結(jié):此種實(shí)現(xiàn)方式相對(duì)復(fù)雜,支持跨域放坏,擴(kuò)展性好咙咽,是單點(diǎn)登錄的標(biāo)準(zhǔn)做法。
四淤年、實(shí)現(xiàn)方式三:LocalStorage跨域
前面钧敞,我們說(shuō)實(shí)現(xiàn)單點(diǎn)登錄的關(guān)鍵在于,如何讓 Session ID(或 Token)在多個(gè)域中共享麸粮。
父域 Cookie 確實(shí)是一種不錯(cuò)的解決方案犁享,但是不支持跨域。那么有沒(méi)有什么奇淫技巧能夠讓 Cookie 跨域傳遞呢豹休?
很遺憾炊昆,瀏覽器對(duì) Cookie 的跨域限制越來(lái)越嚴(yán)格。Chrome 瀏覽器還給 Cookie 新增了一個(gè) SameSite 屬性威根,此舉幾乎禁止了一切跨域請(qǐng)求的 Cookie 傳遞(超鏈接除外)凤巨,并且只有當(dāng)使用 HTTPs 協(xié)議時(shí),才有可能被允許在 AJAX 跨域請(qǐng)求中接受服務(wù)器傳來(lái)的 Cookie洛搀。
不過(guò)敢茁,在前后端分離的情況下,完全可以不使用 Cookie留美,我們可以選擇將 Session ID (或 Token )保存到瀏覽器的 LocalStorage 中彰檬,讓前端在每次向后端發(fā)送請(qǐng)求時(shí),主動(dòng)將 LocalStorage 的數(shù)據(jù)傳遞給服務(wù)端谎砾。這些都是由前端來(lái)控制的逢倍,后端需要做的僅僅是在用戶登錄成功后,將 Session ID (或 Token )放在響應(yīng)體中傳遞給前端景图。
在這樣的場(chǎng)景下较雕,單點(diǎn)登錄完全可以在前端實(shí)現(xiàn)。前端拿到 Session ID (或 Token )后,除了將它寫(xiě)入自己的 LocalStorage 中之外亮蒋,還可以通過(guò)特殊手段將它寫(xiě)入多個(gè)其他域下的 LocalStorage 中扣典。
總結(jié):此種實(shí)現(xiàn)方式完全由前端控制,幾乎不需要后端參與慎玖,同樣支持跨域贮尖。