// CheckTokenEndpoint.checkToken @RequestMapping(value = "/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
不合法,則資源服務器返回給客戶端對應的信息//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; }
token
時,若當前用戶已經存在對應的token,直接返回而不不會建立新 token。token
。token
,有效時間不會和session
機制同樣自動續期。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); } }
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
訪問資源服務器資源java
資源服務器攔截 token
去認證服務器 check_token
git
認證服務器返回 token
過時錯誤,資源服務器包裝錯誤信息返回給客戶端github
客戶端根據返回錯誤信息(響應碼),直接調用認證服務器 refresh_token
shell
認證服務器返回新的 token
給客戶端, 而後再次發起 資源調用服務器
被動請求的缺點是,用戶當次請求會失敗(返回token失敗),對一些業務連貫的操做不是很友好session
客戶端存在計算邏輯,計算下發token 有效期app
若token要過時以前,主動發起刷新curl
主動請求的缺點是,客戶端佔用部分計算資源來處理 token
失效問題ide
// 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.二、 Spring Cloud Hoxton & Alibaba、 OAuth2 的RBAC 權限管理系統