聊聊 OAuth 2.0 的 Token 续期处理
2020-06-08 16:06:10来源:博客园 阅读 ()
聊聊 OAuth 2.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);
}
-
- 当客户端带着
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.cnblogs.com/leng-leng/p/13064887.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- 因为命名被diss无数次。简单聊聊编程最头疼的事情之一:命名 2020-06-10
- 聊聊微服务架构及分布式事务解决方案! 2020-06-10
- Spring Security OAuth 格式化 token 输出 2020-06-08
- 聊聊 OAuth 2.0 的 token expire_in 使用 2020-06-08
- 从聚合支付业务的设计来聊聊策略模式 2020-06-03
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash