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. Captain technology开发的新能源汽车强在哪里?

    在新能源汽车飞速发展的这些年,Captain technology 认识到,要改变有状况,就要不断创新,调整新能源汽车发展路线.新能源汽车本质永远是汽车, Captain technology是在改变 ...

  2. 知名金融媒体采访行业大咖,多方推动BGV茁壮成长

    近来,多家知名金融媒体如纽约金融时报.伦敦金融时报等采访NGK官方代表洛索斯夫,以及美国当地行业大咖马库斯等人. 受访的NGK官方代币洛索斯夫回答道,近期官方将会推出NGK的书籍<NGK公链底层 ...

  3. Docker Tips: 关于/var/run/docker.sock

    本文转载自Docker Tips: 关于/var/run/docker.sock 导语 你可能已经运行过docker hub上的container并且注意到其中的一些需要绑定挂载(mount)/var ...

  4. vue_webpack

    1.生成项目工程描述文件 npm init 2.安装webpack开发依赖 (本地安装):npm install -D 3.(webpack4.0版本以上安装webpack cli) npm inst ...

  5. 图文详解:Kafka到底有哪些秘密让我对它情有独钟呢?

  6. OSS对象储存

    简介 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量.安全.低成本.高可靠的云存储服务. 使用流程 名词解释  Endpoint(访问域名) Ac ...

  7. Oracle 开启或关闭归档

    开启:sqlplus / as sysdbaarchive log list;shutdown immediate;startup mount;alter database archivelog;ar ...

  8. Prometheus+Grafana+Alertmanager搭建全方位的监控告警系统

    prometheus安装和配置 prometheus组件介绍 1.Prometheus Server: 用于收集和存储时间序列数据. 2.Client Library: 客户端库,检测应用程序代码,当 ...

  9. Java RPC 框架 Solon 1.3.7 发布,增强Cloud接口能力范围

    Solon 是一个微型的Java RPC开发框架.项目从2018年启动以来,参考过大量前人作品:历时两年,4000多次的commit:内核保持0.1m的身材,超高的跑分,良好的使用体验.支持:RPC. ...

  10. Java 基础加强 02

    基础加强·反射 和 枚举 类的加载概述和加载时机 * A:类的加载概述 * 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载.连接.初始化来实现对这个类的初始化 * 加载 * 就是指 ...