發(fā)展史和背景
從單體應(yīng)用架構(gòu)到分布式應(yīng)用架構(gòu)再到微服務(wù)架構(gòu),應(yīng)用的架構(gòu)通過不停的改進(jìn)升級的方式滿足不斷擴(kuò)大的業(yè)務(wù)需求。隨著應(yīng)用架構(gòu)的改變,身份認(rèn)證的方式也在發(fā)生變化,為了適應(yīng)架構(gòu)的變化、需求的變化,身份認(rèn)證與鑒權(quán)方案也需要不斷的變革。
在傳統(tǒng)單體應(yīng)用架構(gòu)中,身份認(rèn)證從來都不是問題,簡單粗暴的通過一個(gè)權(quán)限的攔截器,配合session基本都解決了?。ㄟ@里簡單說說session, 因?yàn)镠ttp協(xié)議是一種無狀態(tài)協(xié)議,即每次服務(wù)端接收到客戶端的請求時(shí),都是一個(gè)全新的請求,服務(wù)器并不知道客戶端的歷史請求記錄;session的主要目的就是為了彌補(bǔ)Http的無狀態(tài)特性。簡單的說,就是服務(wù)器可以利用session存儲(chǔ)客戶端在同一個(gè)會(huì)話期間的一些操作記錄。)
在于分布式應(yīng)用架構(gòu)中,也有很多處理方式,最流行無非以下幾種:
- session綁定:即將同一用戶的所有請求都分發(fā)到同一臺服務(wù)器上
優(yōu)點(diǎn):簡單,不需要對session做任何處理
缺點(diǎn):缺乏容錯(cuò)性,如果當(dāng)前訪問的服務(wù)器發(fā)生故障,用戶被轉(zhuǎn)移到第二個(gè)服務(wù)器上時(shí),它的session信息都將失效。 - session復(fù)制:任何一個(gè)服務(wù)器上的session發(fā)生改變(增刪改),該節(jié)點(diǎn)會(huì)把這個(gè)session的所有內(nèi)容序列化,然后廣播給所有其他節(jié)點(diǎn),不管其他服務(wù)器需不需要session,以此來保證session同步。
優(yōu)點(diǎn):可容錯(cuò),各個(gè)服務(wù)器間session能夠?qū)崟r(shí)響應(yīng)。
缺點(diǎn):會(huì)對網(wǎng)絡(luò)負(fù)荷造成一定壓力,如果session量大的話,可能會(huì)造成網(wǎng)絡(luò)堵塞,拖慢服務(wù)器性能。 - session共享:將原本儲(chǔ)存在內(nèi)存中的session,放入一個(gè)公共的緩存當(dāng)中(如redis、memcached),服務(wù)器根據(jù)請求去緩存中讀取session
優(yōu)點(diǎn):可容錯(cuò),服務(wù)器不需要存儲(chǔ)session減少內(nèi)存占用,也是目前最為流行的使用方式
接下主要聊聊在微服務(wù)架構(gòu)中的一些方案和個(gè)人理解
微服務(wù)架構(gòu)中的身份認(rèn)證服務(wù)
一、首先說說 David Borsos 在倫敦的微服務(wù)大會(huì)上提出的四種方案:
1. 單點(diǎn)登錄(SSO)
采用單點(diǎn)登錄方案,意味著每個(gè)面向用戶的服務(wù)都必須與認(rèn)證服務(wù)交互,這會(huì)產(chǎn)生大量非?,嵥榈木W(wǎng)絡(luò)流量,同時(shí)這個(gè)防范實(shí)現(xiàn)起來也相當(dāng)?shù)膹?fù)雜,同時(shí)重構(gòu)相當(dāng)麻煩,因?yàn)樾枰嫒菟邢到y(tǒng)。在其他方面,選擇SSO方案安全性會(huì)很好,用戶登錄狀態(tài)是不透明的,可防止攻擊者從狀態(tài)中推斷任何有用的信息。
2. 分布式session
分布式會(huì)話方案原理主要是將關(guān)于用戶認(rèn)證的信息存儲(chǔ)在共享存儲(chǔ)中,且通常由用戶會(huì)話作為 key 來實(shí)現(xiàn)的簡單分布式哈希映射。當(dāng)用戶訪問微服務(wù)時(shí),用戶數(shù)據(jù)可以從共享存儲(chǔ)中獲取。在某些場景下,這種方案很不錯(cuò),用戶登錄狀態(tài)是不透明的。同時(shí)也是一個(gè)高可用且可擴(kuò)展的解決方案。這種方案的缺點(diǎn)在于共享存儲(chǔ)需要一定保護(hù)機(jī)制,因此需要通過安全鏈接來訪問,這時(shí)解決方案的實(shí)現(xiàn)就通常具有相當(dāng)高的復(fù)雜性了。
3. 客戶端 Token
令牌在客戶端生成,由身份驗(yàn)證服務(wù)進(jìn)行簽名,并且必須包含足夠的信息,以便可以在所有微服務(wù)中建立用戶身份。令牌會(huì)附加到每個(gè)請求上,為微服務(wù)提供用戶身份驗(yàn)證,這種解決方案的安全性相對較好,但身份驗(yàn)證注銷是一個(gè)大問題,緩解這種情況的方法可以使用短期令牌和頻繁檢查認(rèn)證服務(wù)等。對于客戶端令牌的編碼方案,Borsos 更喜歡使用 JSON Web Tokens(JWT),它足夠簡單且?guī)熘С殖潭纫脖容^好。
4. 客戶端 Token 與 API 網(wǎng)關(guān)結(jié)合
這個(gè)方案意味著所有請求都通過網(wǎng)關(guān),從而有效地隱藏了微服務(wù)。 在請求時(shí),網(wǎng)關(guān)將原始用戶令牌轉(zhuǎn)換為內(nèi)部會(huì)話 ID 令牌。在這種情況下,注銷就不是問題,因?yàn)榫W(wǎng)關(guān)可以在注銷時(shí)撤銷用戶的令牌。
二、個(gè)人理解的方案實(shí)現(xiàn) JWT + Zuul + Redis :
其實(shí)就是 客戶端 Token 與 API 網(wǎng)關(guān)結(jié)合 的變相實(shí)現(xiàn)
因?yàn)榇蟛糠治⒎?wù)內(nèi)部直接調(diào)用都默認(rèn)不用再次驗(yàn)證,因此沒有必要再搞一個(gè)內(nèi)部的token,直接將數(shù)據(jù)取出來簡單粗暴的進(jìn)行交互!
但對于一些特殊的應(yīng)用,服務(wù)與服務(wù)之間的調(diào)用也設(shè)計(jì)了權(quán)限,像這種情況生成內(nèi)部token還是確實(shí)有必要的!
若對過期要求不高的場景,可以不使用Redis,直接使用 JWT 的過期時(shí)間即可
登錄流程:

用戶登錄,網(wǎng)關(guān)判斷是不是登錄請求
如果是,則訪問跳轉(zhuǎn)至認(rèn)證微服務(wù)。在認(rèn)證微服務(wù)驗(yàn)證驗(yàn)證通過后,生成JWT(包括有效器,權(quán)限信息或者是轉(zhuǎn)義后的權(quán)限信息等)返回,同時(shí)將一些隱私信息(包括用戶聯(lián)系方式、權(quán)限信息等)存入redis并設(shè)置過期時(shí)間(略大于 JWT 有效期即可),前端存儲(chǔ)JWT,以后的所有請求都需攜帶 JWT
如果不是,則進(jìn)行驗(yàn)證流程
驗(yàn)證流程:

檢查用戶請求是否攜帶token,因?yàn)槭?JWT ,網(wǎng)關(guān)可以判斷token是否有效,無效則直接返回未登錄,有效則向認(rèn)證微服務(wù)請求驗(yàn)證,認(rèn)證微服務(wù)從redis獲取該token對應(yīng)的隱私信息(主要是權(quán)限信息,這里因?yàn)殡[私信息的有效是大于JWT的)認(rèn)證通過后將隱私信息返回給網(wǎng)關(guān),網(wǎng)關(guān)攜帶隱私信息再訪問其它微服務(wù)
關(guān)鍵點(diǎn)描述說明
- 服務(wù)端如何控制token失效?
當(dāng)用戶修改密碼后,直接將redis中的該用戶的隱私信息刪除掉即可!
當(dāng)用戶的權(quán)限被修改后,直接修改存儲(chǔ)在redis中的權(quán)限即可,當(dāng)用戶下一次請求過來時(shí),后端自動(dòng)若發(fā)現(xiàn)權(quán)限變化了,則自動(dòng)再生成一個(gè)token返回給前端,前端重新存儲(chǔ)下token。這樣用戶既可以不用重新登錄,而且權(quán)限又得到了很好的控制! - 為什么要將權(quán)限存入redis?
有人可能會(huì)說,JWT中已經(jīng)有權(quán)限信息了,為什么我們還需要在redis中保存?JWT不是基本上可以默認(rèn)為是無法被篡改的嗎?這個(gè)主意是考慮到用戶的權(quán)限可能會(huì)發(fā)生變化,JWT中的權(quán)限只是在前端用來控制UI元素顯示或是否可點(diǎn)擊的,因?yàn)槲曳桨甘且骉oken失效是后臺可以隨意掌控的,不管權(quán)限放不放redis,每次的token驗(yàn)證都是必須查redis的,因此將權(quán)限放入redis還可以動(dòng)態(tài)改變!