Token 校驗邏輯
// CheckTokenEndpoint.checkToken
@RequestMapping(value = "https://www.cnblogs.com/oauth/check_token")
@ResponseBody
public Map<String, ?> checkToken(@RequestParam("token") String value) {
// 根據 token 查詢保存在 tokenStore 的令牌全部資訊
OAuth2AccessToken token = resourceServerTokenServices.readAccessToken(value);
if (token == null) {
throw new InvalidTokenException("Token was not recognised");
}
if (token.isExpired()) {
throw new InvalidTokenException("Token has expired");
}
// 根據 token 查詢保存的 認證資訊 還有權限角色等 (業務資訊)
OAuth2Authentication authentication = resourceServerTokenServices.loadAuthentication(token.getValue());
return accessTokenConverter.convertAccessToken(token, authentication);
}
-
- 當客戶端帶著
header token訪問oauth2資源服務器,資源服務器會自動攔截token
- 當客戶端帶著
-
- 發送
token到 認證服務器 校驗token合法性
- 發送
-
- 若認證服務器回傳給資源服務器是
token不合法,則資源服務器回傳給客戶端對應的資訊
- 若認證服務器回傳給資源服務器是
Token 生成邏輯
//DefaultTokenServices.createAccessToken 代碼邏輯
public OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) throws AuthenticationException {
// 根據用戶資訊(username),查詢已下發的token
OAuth2AccessToken existingAccessToken = tokenStore.getAccessToken(authentication);
OAuth2RefreshToken refreshToken = null;
// 存在已下發的token
if (existingAccessToken != null) {
// 1. token 已經被標志過期,則洗掉
if (existingAccessToken.isExpired()) {
if (existingAccessToken.getRefreshToken() != null) {
refreshToken = existingAccessToken.getRefreshToken();
tokenStore.removeRefreshToken(refreshToken);
}
tokenStore.removeAccessToken(existingAccessToken);
}
else {
// 直接回傳存在的 token,并保存一下token 和 用戶資訊的關系 (username)
tokenStore.storeAccessToken(existingAccessToken, authentication);
return existingAccessToken;
}
}
// 不存在則創建新的 token
OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);
tokenStore.storeAccessToken(accessToken, authentication);
// In case it was modified
refreshToken = accessToken.getRefreshToken();
if (refreshToken != null) {
tokenStore.storeRefreshToken(refreshToken, authentication);
}
return accessToken;
}
-
- 當我們通過oauth2 去獲取
token時,若當前用戶已經存在對應的token,直接回傳而不不會創建新 token,
- 當我們通過oauth2 去獲取
-
- 這就意味著,雖然設定了對應客戶端獲取 token 的有效時間,這里獲取到的
token,
若是已下發舊token,有效時間不會和session機制一樣自動續期,
- 這就意味著,雖然設定了對應客戶端獲取 token 的有效時間,這里獲取到的
-
- 綜上情況,在操作程序中
token過期是一個常態化的問題,
- 綜上情況,在操作程序中
Token 重繪邏輯
curl --location --request POST 'http://auth-server/oauth/token?grant_type=refresh_token' \
--header 'Authorization: Basic dGVzdDp0ZXN0' \
--header 'VERSION: dev' \
--data-urlencode 'scope=server' \
--data-urlencode 'refresh_token=eccda61e-0c68-43af-8f67-6302cb389612'
若上,當 前端拿著正確的(未過期且未使用過)refresh_token 去呼叫 認證中心的重繪 端點重繪時,會 觸發RefreshTokenGranter, 回傳新的 Token
public class RefreshTokenGranter extends AbstractTokenGranter {
@Override
protected OAuth2AccessToken getAccessToken(ClientDetails client, TokenRequest tokenRequest) {
String refreshToken = tokenRequest.getRequestParameters().get("refresh_token");
return getTokenServices().refreshAccessToken(refreshToken, tokenRequest);
}
}
- refreshAccessToken 代碼實作,呼叫
tokenStore生成新的token
@Transactional(noRollbackFor={InvalidTokenException.class, InvalidGrantException.class})
public OAuth2AccessToken refreshAccessToken(String refreshTokenValue, TokenRequest tokenRequest)
throws AuthenticationException {
createRefreshedAuthentication(authentication, tokenRequest);
if (!reuseRefreshToken) {
tokenStore.removeRefreshToken(refreshToken);
refreshToken = createRefreshToken(authentication);
}
OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);
tokenStore.storeAccessToken(accessToken, authentication);
if (!reuseRefreshToken) {
tokenStore.storeRefreshToken(accessToken.getRefreshToken(), authentication);
}
return accessToken;
}
客戶端(前端)何時重繪
被動重繪

-
客戶端攜帶
token訪問資源服務器資源 -
資源服務器攔截
token去認證服務器check_token -
認證服務器回傳
token過期錯誤,資源服務器包裝錯誤資訊回傳給客戶端 -
客戶端根據回傳錯誤資訊(回應碼),直接呼叫認證服務器
refresh_token -
認證服務器回傳新的
token給客戶端, 然后再次發起 資源呼叫
被動請求的缺點是,用戶當次請求會失敗(回傳token失敗),對一些業務連貫的操作不是很友好
主動重繪

-
客戶端存在計算邏輯,計算下發token 有效期
-
若token要過期之前,主動發起重繪
主動請求的缺點是,客戶端占用部分計算資源來處理 token 失效問題
// 10S檢測token 有效期
refreshToken() {
this.refreshTime = setInterval(() => {
const token = getStore({
name: 'access_token',
debug: true
})
if (this.validatenull(token)) {
return
}
if (this.expires_in <= 1000 && !this.refreshLock) {
this.refreshLock = true
this.$store
.dispatch('RefreshToken')
.catch(() => {
clearInterval(this.refreshTime)
})
this.refreshLock = false
}
this.$store.commit('SET_EXPIRES_IN', this.expires_in - 10)
}, 10000)
},
『★★★★★』 基于Spring Boot 2.2、 Spring Cloud Hoxton & Alibaba、 OAuth2 的RBAC 權限管理系統
專案推薦: Spring Cloud 、Spring Security OAuth2的RBAC權限管理系統 歡迎關注
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/168982.html
標籤:Java
