個人感覺啊
Spring Security OAuth2
功能很強大、但是如果要做改動的話就需要好好研究研究了、
OAuth2
有好幾種授權模式裡、我最常用的也就是
password
模式、
授權碼
模式略微複雜、沒咋研究過、而且感覺這個架構隻使用網站的時候使用授權碼方式對第三方系統進行授權是最簡單的、要不感覺就需要深入研究了、最主要的還是根據需求來做決定、一般使用者這塊無非就是以下幾種關系
- 同一使用者(任何端)可無限制線上
- 同一使用者隻可同時線上一個或多個
- 同一使用者不同端同時可線上一個或多個(例如:app、網站等等)
在
OAuth2
中有一個很重要的接口就是
TokenStore
接口、該接口就是為了生成token的、當然也可以儲存token、移除token等等、其内有很多方法、有興趣可以去看一看、而
RedisTokenStore
和
JwtTokenStore
就是該接口的實作類
其中還有個重要的接口
AuthorizationServerTokenServices
、該接口預設實作類是
DefaultTokenServices
、該類在使用者進行授權的時候會執行
createAccessToken
方法
@Transactional
public OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) throws AuthenticationException {
//調用tokenStore的getAccessToken方法、在使用Jwt時、JwtTokenStore的該方法傳回為null
//RedisTokenStore的話會去查詢目前是否存在該使用者的Token、如果不存在則傳回null
OAuth2AccessToken existingAccessToken = this.tokenStore.getAccessToken(authentication);
OAuth2RefreshToken refreshToken = null;
if (existingAccessToken != null) {
//以下這個if塊中的代碼就是為啥在使用Redis的時候、如果token未過期不會再次生成的原因
if (!existingAccessToken.isExpired()) {
this.tokenStore.storeAccessToken(existingAccessToken, authentication);
return existingAccessToken;
}
//如果上面那句沒被return、這裡看看重新整理token是否為null、不為null的話就把重新整理token移除
if (existingAccessToken.getRefreshToken() != null) {
refreshToken = existingAccessToken.getRefreshToken();
this.tokenStore.removeRefreshToken(refreshToken);
}
//移除token
this.tokenStore.removeAccessToken(existingAccessToken);
}
if (refreshToken == null) {//這個是擷取重新整理token的代碼
refreshToken = this.createRefreshToken(authentication);
} else if (refreshToken instanceof ExpiringOAuth2RefreshToken) {
ExpiringOAuth2RefreshToken expiring = (ExpiringOAuth2RefreshToken)refreshToken;
if (System.currentTimeMillis() > expiring.getExpiration().getTime()) {
refreshToken = this.createRefreshToken(authentication);
}
}
//這裡是生成existingAccessToken 為空或者最上面那個if塊并沒有被return的時候執行的
//建立token代碼、這裡需要說一下、createAccessToken在Jwt的時候需要額外關注一下、在下面介紹該方法
OAuth2AccessToken accessToken = this.createAccessToken(authentication, refreshToken);
this.tokenStore.storeAccessToken(accessToken, authentication);//儲存token
refreshToken = accessToken.getRefreshToken();
if (refreshToken != null) {
this.tokenStore.storeRefreshToken(refreshToken, authentication);//儲存重新整理token的
}
return accessToken;
}
接下來解析
DefaultTokenServices
的
createAccessToken(OAuth2Authentication, OAuth2RefreshToken)
方法、該方法在使用Jwt生成token時很重要、最重要的在最後一行、大白話就是如果
accessTokenEnhancer
不為null那麼就調用
accessTokenEnhancer
來生成token否者就傳回目前
DefaultOAuth2AccessToken
類生成的token
private OAuth2AccessToken createAccessToken(OAuth2Authentication authentication, OAuth2RefreshToken refreshToken) {
DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(UUID.randomUUID().toString());
int validitySeconds = this.getAccessTokenValiditySeconds(authentication.getOAuth2Request());
if (validitySeconds > 0) {
token.setExpiration(new Date(System.currentTimeMillis() + (long)validitySeconds * 1000L));
}
token.setRefreshToken(refreshToken);
token.setScope(authentication.getOAuth2Request().getScope());
//TokenEnhancer接口
return (OAuth2AccessToken)(this.accessTokenEnhancer != null ? this.accessTokenEnhancer.enhance(token, authentication) : token);
}
而
JwtTokenStore
類需要一個
JwtAccessTokenConverter
類來作為構造函數的參數、主要用于解析和驗證Jwt生成的token的、
DefaultTokenServices
類也需要、是以這裡就需要分别配置
TokenStore
和
TokenEnhancer
、兩個必須都配置
總結來說
RedisTokenStore
隻要該token不過期、永遠使用的都是一個token、不知道有沒有别的方法可以不這樣、我找了好多都沒找到、而
JwtTokenStore
則是每次都生成不同的token、感覺可以使用
RedisTokenStore
來儲存token、然後自定義
TokenEnhancer
來生成token、我也沒試過不知道能不能行