歡迎關注全是干貨的技術公眾號:JavaEdge
本文主要內容:
- 如何實現用戶認證與授權?
- 實現的三種方案,全部是通過畫圖的方式講解.以及三種方案的對比
- 最后根據方案改造Gateway和擴展Feign
0 相關源碼
1 有狀態 vs 無狀態
1.1 有狀態
也可使用粘性會話,即:對相同IP的請求,NGINX總 會轉發到相同的Tomcat實例,這樣就就無需圖中的Session Store了。不過這種方式有很多缺點:比如用戶斷網重連,刷新頁面,由於IP變了,NGINX會轉發到其他Tomcat實例,而其他實例沒有Session,於是就認為用戶未登錄。這讓用戶莫名其妙。
粘性會話不是本章重點,如果感興趣可以百度一下(用得越來越少了)
1.2 無狀態
這里講的是解密Token直接拿到用戶信息;事實上要看項目的具體實現;有時候Token里不一定帶有用戶信息;而是利用Token某個地方查詢,才能獲得用戶信息。
1.3 對比小結
2 微服務認證方案
2.1 “處處安全”
推薦閱讀
代表實現
- Spring Cloud Security : https://cloud. spring.io/spring-cloud-security/reference/html/
- Jboss Keycloak : https://www.keycloak.org
示例代碼
- Spring Cloud Security認證授權示例代碼
- Keycloak認證授權示例代碼(基於Servlet實現,無法和SpringCloudGateway整合)
優劣分析
安全性好
但是實現成本高,而且多次token交換和認證,所以有性能開銷
2.2 外部無狀態,內部有狀態
- 架構過於復雜,微服務和傳統架構混合雙搭
2.3 網關認證授權,內部裸奔
登錄成功后,網關頒發token,之后用戶的每個請求都會攜帶該token,網關對其解密是否合法,過期等,token中會攜帶用戶信息,所以網關還可解析token即可知道用戶是誰,比如解析出了id和name,就會將其加入請求的header中進行轉發,每個服務就知道是啥子用戶啦!
優劣
優點是實現簡單,性能佳,但是一旦網關的登錄認證被攻破,就涼了
2.4 “內部裸奔”改進方案
請求經過網關到認證授權中心去登錄,成功則頒發token,之后用戶請求都會攜帶該token,但是網關不對token做操作
這樣降低了網關的設計復雜度,網關不再關注用戶是誰了(不再解密解析token),只負責轉發
讓系統也避免了裸奔的尷尬
但是要想解密token,還是需要密鑰,現在每個微服務都要去做解密工作,意味着每個服務都知道密鑰了.被泄露的風險隨之增大,需要防止這種情況,可以定期更新密鑰,想辦法不讓開發直接看到密鑰本身(但是一般吧,除非有內部腦殘人士才會泄露密鑰,一般還是很安全的)
優劣分析
實現並不復雜,降低了網關的復雜度,但是密鑰如果泄露了,就完了,這個可以借助后面的方法避免,先留坑
2.5 方案對比與選擇
3 訪問控制模型(授權)
- Access Control List (ACL)
- Role-based access control (RBAC 最流行)
- Attribute- based access control (ABAC)
- Rule-based access control
- Time-based access control
我們使用的token其實就是JWT,what's that?
4 JWT
4.1 定義
JWT全稱Json web token ,是一個開放標准(RFC 7519) ,用來在各方之間安全地傳輸信息。JWT可被驗證和信任,因為它是數字簽名的。
4.2 組成
4.3 公式
token算法
- Token = Base64(Header).Base64(Payload).Base64(Signature)
示例: aaaa.bbbbb.ccccc
簽名算法
◆ Signature = Header指定的簽名算法
(Base64(header).Base64(payload), 秘鑰)
● 秘鑰: HS256("aaaa.bbbbb",秘鑰)
-
推薦閱讀
JWT操作工具類分享 -
為用戶中心引入JWT
-
引入工具類后生成的JWT,並新建JWT操作類,並簡單測試生成JWT
-
寫配置
-
同樣的方式為內容中心添加JWT配置,不再贅述,注意secret都保持一致
5 實現認證授權
實現小程序登錄
- 小程序登錄流程,我們java代碼需要做的就是實現圖中的4,5,6步驟
- 用戶點擊登錄按鈕后,彈出如下,點擊允許,即表示同意獲取個人信息
- login
- 在用戶中心新建 dto類
- 小程序API工具包
◆WxJava : https://github.com/Wechat-Group/WxJava - 在用戶中心添加依賴
服務實現
6 AOP實現登錄狀態檢查
實現方式
- Servlet過濾器
- filter攔截器
- Spring AOP
我們當然使用優雅地AOP切面編程這種可插拔的方式
6.1 用戶中心
- 引入依賴
- 定義注解
具體代碼看github
6.2 內容中心
與用戶中心類似,不再贅述
使用feign時並沒有傳遞token,所以當做未認證處理
6.2.1 Feign實現Token傳遞
實現方式 @RequestHeader
- 修改控制器,之后將編譯報錯的代碼都注釋掉
需要修改控制器,這不好,棄用
實現方式 RequestInterceptor
實現方式 RestTemplate實現Token傳遞
exchange()
ClientHttpRequestInterceptor
7 AOP實現用戶權限驗證 - 授權
- 需求:用戶role須是管理員才有權訪問
7.1 實現方案 - 土方法
- 通過注入的屬性值判斷,對於API多的就不合時宜了!
當然你用過濾器,攔截器實現也是可以的.
7.2 優雅地用AOP實現
- 定義注解
- 控制器方法上添加注解
- 修改網關配置
總結
◆ 登錄認證的四種方案
◆ AOP實現認證授權
◆ N種訪問控制模型
◆ Feign傳遞Token
◆ JWT
◆ RestTemplate傳遞Token