采用令牌的方式可以讓用戶靈活地對第三方應用授權或者收回權限,OAuth2是OAuth協議的下一個版本,但不向下兼容OAuth 1.0。OAuth2關注客戶端開發者的簡易性,同時為Web應用、桌面應用、移動設備、起居室設備提供專門的認證流程,傳統的Web開發登錄認證一般都是基於Session的,但是前后端分離的架構中繼續使用Session會有很多不便,因為移動端要么不支持cookie(微信小程序),要么使用非常不便,對於這些問題,使用OAuth2認證都能解決。
OAuth2授權有4種模式,我們自己做前后端分離登錄就可以采用密碼模式。微服務中有一個特殊的場景,就是服務之間的調用,用密碼模式做鑒權是非常恰當不過的了
0.OAuth2中的角色都有哪些?
0.1 資源擁有者
可以是一個人也可以是一個公司實體,對資源持有的實體。
0.2 資源服務
受保護的資源,可以使用token令牌來訪問
0.3 客戶端
需要請求資源的應用客戶端,PC,APP
0.4 認證服務
發放令牌的服務,驗證資源所有者並獲得授權
1.為什么要用無狀態服務的代替有狀態服務的?
有狀態服務,即服務端需要記錄每次會話的客戶端信息,從而識別客戶端身份,根據用戶身份進行請求的處理,典型的設計如 Tomcat 中的 Session。例如登錄:用戶登錄后,我們把用戶的信息保存在服務端 session 中,並且給用戶一個 cookie 值,記錄對應的 session,然后下次請求,用戶攜帶 cookie 值來(這一步有瀏覽器自動完成),我們就能識別到對應 session,從而找到用戶的信息。這種方式目前來看最方便,但是也有一些缺陷,如下:
- 服務端保存大量數據,增加服務端壓力
- 服務端保存用戶狀態,不支持集群化部
2.無狀態性有哪些好處呢?
- 客戶端請求不依賴服務端的信息,多次請求不需要必須訪問到同一台服務器
- 服務端的集群和狀態對客戶端透明
- 服務端可以任意的遷移和伸縮(可以方便的進行集群化部署)
- 減小服務端存儲壓力
3.如何實現無狀態?無狀態的登陸流程:
- 首先客戶端發送賬戶名/密碼到服務端進行認證
- 認證通過后,服務端將用戶信息加密並且編碼成一個 token,返回給客戶端
- 以后客戶端每次發送請求,都需要攜帶認證的 token
- 服務端對客戶端發送來的 token 進行解密,判斷是否有效,並且獲取用戶登錄信息
4.JWT存在的問題:
- 續簽問題,這是被很多人詬病的問題之一,傳統的 cookie+session 的方案天然的支持續簽,但是 jwt 由於服務端不保存用戶狀態,因此很難完美解決續簽問題,如果引入 redis,雖然可以解決問題,但是 jwt 也變得不倫不類了。
- 注銷問題,由於服務端不再保存用戶信息,所以一般可以通過修改 secret 來實現注銷,服務端 secret 修改后,已經頒發的未過期的 token 就會認證失敗,進而實現注銷,不過畢竟沒有傳統的注銷方便。
- 密碼重置,密碼重置后,原本的 token 依然可以訪問系統,這時候也需要強制修改 secret。
- 基於第 2 點和第 3 點,一般建議不同用戶取不同 secret
5.單純的使用OAuth2的password模式有問題嗎?
我們知道授權服務器派發了 access_token 之后,客戶端拿着 access_token 去請求資源服務器,資源服務器要去校驗 access_token 的真偽,所以我們在資源服務器上配置了 RemoteTokenServices,讓資源服務器做遠程校驗
@Bean RemoteTokenServices tokenServices() { RemoteTokenServices services = new RemoteTokenServices(); services.setCheckTokenEndpointUrl("http://localhost:8080/oauth/check_token"); services.setClientId("javaboy"); services.setClientSecret("123"); return services; }
在高並發環境下這樣的校驗方式顯然是有問題的,如果結合 JWT,用戶的所有信息都保存在 JWT 中,這樣就可以有效的解決上面的問題。
6. OAuth2中存儲令牌的方式:
我們可以把令牌存儲在內存中,但是如果部署多個服務,就會導致無法使用令牌的問題。 Spring Cloud Security中有兩種存儲令牌的方式可用於解決該問題,一種是使用Redis來存儲,另一種是使用JWT來存儲