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

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

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