OAuth 2.0 簡單介紹
**角色**:先區分下OAuth 2.0 中有哪些角色,注意這里根據自己理解來寫的,阮一峰博客里寫的更精確:
Client: 客戶端,也就是Third-party application - 第三方應用程序
Service:服務端,也就是服務的提供者
User: 用戶,也就是Resource Owner - 資源所有者
User Agent:用戶代理,如瀏覽器,下文中將其與Client合并考慮。
Authorization Server:認證服務器,即服務提供商專門用來處理認證的服務器。
Resource Server:資源服務器,即服務提供商存放用戶生成的資源的服務器。
**模式**
在不需要第三方認證支持時,我們常用的就是簡化模式:
(A)客戶端將用戶導向認證服務器。
(B)用戶決定是否給于客戶端授權。
(C)假設用戶給予授權,認證服務器將用戶導向客戶端指定的"重定向URI",并在URI的Hash部分包含了訪問令牌。
(D)瀏覽器向資源服務器發出請求,其中不包括上一步收到的Hash值。
(E)資源服務器返回一個網頁,其中包含的代碼可以獲取Hash值中的令牌。
(F)瀏覽器執行上一步獲得的腳本,提取出令牌。
(G)瀏覽器將令牌發給客戶端。
**Spring Cloud 微服務下**
Spring Cloud 下我們這里使用簡化模式,主要是登錄、授權、Token管理,角色大體如下:
User: 也就是用戶,用戶一般直接與Client交互,REST API后臺一般不需要考慮。
Gateway + Resource Server :資源服務器對請求進行認證,一般整合在網關中,這樣可以很方便的統一處理所有請求。
Authorization Server: 授權服務器,進行授權和Token管理。
Client: 調用API的應用,一般是前端、移動App或者第三方應用
Token Store: 令牌存儲,多個服務如果每次請求都通過授權服務器進行Token查詢,效率底下,所以需要統一存儲、交互令牌信息,常用Redis
Services: 提供正在業務/功能/API的服務。
大概畫個圖,這里以Client為前端為例,注意不涉及用戶和前端的交互:
**JWT 簡介**
JWT -- Json Web Token, 如其名,使用Json方式保存Web Token的協議。網上有各種解讀,個人理解,這就是一個 客戶端Session - Session保存在客戶端,而不是通常的保存在服務端。
構成
JWT三部分組成:
Header 頭部:JSON方式描述JWT基本信息,如類型和簽名算法。使用Base64編碼為字符串
Payload 載荷:JSON方式描述JWT信息,除了標準定義的,還可以添加自定義的信息。同樣使用Base64編碼為字符串。
iss: 簽發者
sub: 用戶
aud: 接收方
exp(expires): unix時間戳描述的過期時間
iat(issued at): unix時間戳描述的簽發時間
Signature 簽名:將前兩個字符串用 . 連接后,使用頭部定義的加密算法,利用密鑰進行簽名,并將簽名信息附在最后。
注意: Payload 使用 Base64編碼,所以就是明文的,不要存放任何機密信息。
優缺點
當然帶來一些好處:
服務端內存占用少了
不需要維護session狀態了,真正無狀態
單點登錄 so easy,只要后臺服務能解讀,Cookie 設置為頂級域名
有好處當然就有不太好的:
每個請求就要對JWT進行解密,驗證
Token有效期只有超時,沒有退出。當然有一些做法,上面也提到了,jwt-authentication-how-to-implement-logout
XSS攻擊問題,一個討論: Is it OK to store the JWT in local/session storage
我個人的看法是: 使用JWT,同時在Redis保存信息,在API網關進行詳細的驗證;各服務則只簡單校驗Token本身是否篡改。
Spring Cloud OAuth 解讀
角色
Spring Cloud OAuth中將角色為三個,這點從源碼中包org.springframework.security.oauth2.config.annotation.web.configurers 中包含三個Enable注解就可以看出來:
EnableAuthorizationServer -- 使能授權服務器
EnableResourceServer -- 使能資源服務器
EnableOAuth2Client -- 使能客戶端,如需要第三方授權來調用,應該使用此注解。
AuthorizationServer 授權服務配置
一. 首先當然需要使能,在配置類或 Application 上類添加注解: @EnableAuthorizationServer,添加該注解后會自動添加OAuth2的多個endpoint, 相關實現代碼在包 org.springframework.security.oauth2.provider.endpoint:
/oauth/authorize:驗證接口, AuthorizationEndpoint
/oauth/token:獲取token
/oauth/confirm_access:用戶授權
/oauth/error:認證失敗
/oauth/check_token:資源服務器用來校驗token
/oauth/token_key:jwt模式下獲取公鑰;位于:TokenKeyEndpoint ,通過 JwtAccessTokenConverter 訪問key
二. 配置入口為接口:AuthorizationServerConfigurer, 通過擴展AuthorizationServerConfigurerAdapter 實現來進行配置。
Spring Boot 2中很多 Adapter已經取消,直接利用 Java8 Interface Default特性來實現,不過到我寫此文時 security 還沒改,當然也許是我沒注意到。
三. 簡單看一下 AuthorizationServerConfigurer 接口的方法, 一共配置三個屬性:
AuthorizationServerSecurityConfigurer :聲明安全約束,哪些允許訪問,哪些不允許訪問。配置 AuthorizationServer 的安全屬性,也就是endpoint /oauth/token 。/oauth/authorize 則和其它用戶 REST 一樣保護。可以不配置。
ClientDetailsServiceConfigurer : 配置 ClientDetailsService 獨立client客戶端的信息。包括權限范圍、授權方式、客戶端權限等配置。授權方式有4種:implicit, client_redentials, password , authorization_code, 其中密碼授權方式必須結合 AuthenticationManager 進行配置。必須至少配置一個客戶端。
AuthorizationServerEndpointsConfigurer : 配置AuthorizationServer 端點的非安全屬性,也就是 token 存儲方式、token 配置、用戶授權模式等。默認不需做任何配置,除非使用 密碼授權方式, 這時候必須配置 AuthenticationManager。
四. 其中,Token管理:
Token 生命周期管理接口 AuthorizationServerTokenServices, 默認使用: DefaultTokenServices。
Token存儲通過配置 TokenStore,默認使用內存存儲。AuthorizationServerEndpointsConfigurer 或 DefaultTokenServices 入口配置。配置方式有
InMemoryTokenStore 默認方式,保存在本地內存
JdbcTokenStore 存儲數據庫
RedisTokenStore 存儲Redis,這應該是微服務下比較常用方式
JwtTokenStore
AccessTokenConverter
五. 加密算法配置
在spring5之后,必須配置加密算法。
測試時候可以用無加密算法,參考:no-passwordencoder-mapped-id-null
@SuppressWarnings("deprecation")
@Bean
public NoOpPasswordEncoder passwordEncoder() {
return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
}
配置加密算法,當然也可以配置其它算法:
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
具體參考:
https://www.jianshu.com/p/4089c9cc2dfd