聊聊OAuth2.0的Token续期处理

编程

Token 校验逻辑

// 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);

}

    1. 当客户端带着 header token 访问 oauth2 资源服务器,资源服务器会自动拦截 token

    1. 发送 token 到 认证服务器 校验 token 合法性

    1. 若认证服务器返回给资源服务器是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;

}

    1. 当我们通过oauth2 去获取 token 时,若当前用户已经存在对应的token,直接返回而不不会创建新 token。

    1. 这就意味着,虽然设置了对应客户端获取 token 的有效时间,这里获取到的token

      若是已下发旧token,有效时间不会和session 机制一样自动续期。

    1. 综上情况,在操作过程中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;

}

客户端(前端)何时刷新

被动刷新

  1. 客户端携带 token 访问资源服务器资源

  2. 资源服务器拦截 token 去认证服务器 check_token

  3. 认证服务器返回 token 过期错误,资源服务器包装错误信息返回给客户端

  4. 客户端根据返回错误信息(响应码),直接调用认证服务器 refresh_token

  5. 认证服务器返回新的 token 给客户端, 然后再次发起 资源调用

被动请求的缺点是,用户当次请求会失败(返回token失败),对一些业务连贯的操作不是很友好

主动刷新

  1. 客户端存在计算逻辑,计算下发token 有效期

  2. 若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权限管理系统 欢迎关注

以上是 聊聊OAuth2.0的Token续期处理 的全部内容, 来源链接: utcz.com/z/514669.html

回到顶部