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

聊聊 OAuth 2.0 的 Token 续期处理的更多相关文章

  1. 我也想聊聊 OAuth 2.0 —— Access Token

    这是一篇待在草稿箱半年之久的文章 连我自己都不知道我的草稿箱有多少未发布的文章了.这应该是我在上一家公司未解散之前写的,记得当时是要做一个开发者中心,很不幸. 今天,打开草稿箱有种莫名的伤感,看到这个 ...

  2. 聊聊 OAuth 2.0 的 token expire_in 使用

    问题背景 有同学私信问了这样的问题,访问 pig4cloud 的演示环境 查看登录请求 network 返回报文如下: { "access_token":"16d3579 ...

  3. 我也想聊聊 OAuth 2.0 —— 基本概念

    这是一篇待在草稿箱半年之久的文章 连我自己都不知道我的草稿箱有多少未发布的文章了.这应该是我在上一家公司未解散之前写的,记得当时是要做一个开发者中心,很不幸. 今天,打开草稿箱有种莫名的伤感,看到这个 ...

  4. OAuth 2.0: Bearer Token Usage

    Bearer Token (RFC 6750) 用于HTTP请求授权访问OAuth 2.0资源,任何Bearer持有者都可以无差别地用它来访问相关的资源,而无需证明持有加密key.一个Bearer代表 ...

  5. Bearer Token & OAuth 2.0

    Bearer Token & OAuth 2.0 access token & refresh token http://localhost:8080/#/login HTTP Aut ...

  6. ASP.NET WebApi OWIN 实现 OAuth 2.0

    OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用. OAuth 允许用户提供一个令牌, ...

  7. NET WebApi OWIN 实现 OAuth 2.0

    NET WebApi OWIN 实现 OAuth 2.0 OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和 ...

  8. [转]ASP.NET WebApi OWIN 实现 OAuth 2.0

    OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用. OAuth 允许用户提供一个令牌, ...

  9. IdentityServer4 ASP.NET Core的OpenID Connect OAuth 2.0框架学习保护API

    IdentityServer4 ASP.NET Core的OpenID Connect OAuth 2.0框架学习之保护API. 使用IdentityServer4 来实现使用客户端凭据保护ASP.N ...

随机推荐

  1. NGK八大板块:为何郊区市场近来火爆?-VALAITIS, PETER ANTHONY分析

    PAUL ADAMS ARCHITECT LTD董事长VALAITIS, PETER ANTHONY称受大环境影响很多纽约人都选择离开纽约市中心,搬往附近郊区,因此附近地区楼市开始不断升温. 根据房地 ...

  2. 启动Turtlesim,输入roscore命令,报错

    Error: Traceback (most recent call last):   File "/opt/ros/indigo/lib/python2.7/dist-packages/r ...

  3. 关于Sidecar Pattern

    本文转载自关于Sidecar Pattern 导语 Sidecar 是一个很纠结的名字,我们在翻译技术雷达时采用了一个比较通俗的翻译,即边车,而这个词随着微服务的火热与 Service Mesh 的逐 ...

  4. JQuery:JQuery基本语法,JQuery选择器,JQuery DOM,综合案例 复选框,综合案例 随机图片

    知识点梳理 课堂讲义 1.JQuery快速入门 1.1.JQuery介绍 jQuery 是一个 JavaScript 库. 框架:Mybatis (jar包) 大工具 插件:PageHelper (j ...

  5. sql注入和union all关联查询的学习总结

    1.后台从页面取值进行sql查询时最好不要直接拼,如下代码: String sql = "SELECT wo.* " + " from push_command pu & ...

  6. ============================================ 新的开始(前后端分离项目学习Vue+DRF)

  7. setScaledContents

    ui->catchPhotoLabel_607->setPixmap(QPixmap::fromImage(*m_imageCatchtDefaultPhoto_607).scaled(Q ...

  8. PID算法验证

    算法: struct PID { float kp; float kpnfac; float ki; float kinfac; float kd; }; float gCurPPM = 1300; ...

  9. 一次Ubuntu16.04 虚拟机挂起,ping不到网络引发的思考

    虚拟机挂起 无网络 情况复现 can@ubuntu:~$ ping www.baidu.com ping: unknown host www.baidu.com 挂起重开虚拟机,遇到无网络状态: 首先 ...

  10. macOS下Chrome和Safari导入证实抓包HTTPS

    目录 下载证书 mac OS导入证书 Chrome设置代理 Safari设置代理 下面的操作基于Mac OS Catalina(v10.15.3),抓包拦截工具基于Burp Suite v2.1.05 ...