《玄学bug系列(二)-auth2中removeAccessToken清除token信息不全》首发转发请加此提示
欢迎大家观看玄学bug系列第二篇,好久没遇到值得写篇文章描述的bug了,话不多说吗,直接开干。
玄学程度5颗星。难度4颗星,爆肝程度一天。
本文所说oauth2版本为2.3.6
正式所用环境为Redis集群环境
本文所说的tokenStore是oauth2中的RedisTokenStore这个类,所以我的token信息是存在于redis服务器中的。
简单的介绍了一下我的项目结构,我们是一个微服务项目,所以我们有自己的认证中心,也就是oauth2
认证中心。这次出现的问题就在正式环境下,权限信息,清除不掉。但是开发环境,以及测试环境是正常的。我的系统只有在退出登录会调用removeAccessToken方法的情况下会清除token信息。清除完token后正常情况是会掉线的,也就是需要重新获取token。正常情况下是会重新查表,然后缓存到redis。这次正式环境出的问题就是清除token信息不全。导致用户重新登录后,获取的还是老token信息。也就是RedisTokenStore.removeAccessToken在正式环境出了bug,清除token信息不全。
这里先给大家普及下,在我的oauth2认证服务中,如果登录成功,会往redis插入9条信息。分别是:
这里我主要讲两个:access
auth_to_access
这两个存的都是用户的token信息
(一模一样)。但是生成的redis
key的规则不一样。``access是跟据 access
+ token序列化后的值作为key。把**token**存进去。
auth_to_access是以auth_to_access为前缀+username+client_id+scope的值md5加密后作为key存在redis中。其实别看它生成那么多,其实最终存入**redis**中的东西都是一样的。其中我这边爆出生产问题的就是因为
auth_to_access`为前缀的token值没删除掉。
发现这个问题后,我第一时间就反应过来了,查看redis集群看看是否**token
没有清除掉。果不其然。有一个token
信息没有清理掉。前缀为auth_to_access**的token信息没清除掉。
知道这个问题后,第一时间我就去看了退出登录这个方法
@DeleteMapping("/{token}")
public R<Boolean> delToken(@PathVariable("token") String token) {
OAuth2AccessToken accessToken = tokenStore.readAccessToken(token);
if (accessToken == null || StrUtil.isBlank(accessToken.getValue())) {
return R.ok(Boolean.TRUE, "退出失败,token 无效");
}
OAuth2Authentication auth2Authentication = tokenStore.readAuthentication(accessToken);
// 清空用户信息
cacheManager.getCache(CacheConstants.USER_DETAILS)
.evict(auth2Authentication.getName());
// 清空access token
tokenStore.removeAccessToken(accessToken);
// 清空 refresh token
OAuth2RefreshToken refreshToken = accessToken.getRefreshToken();
tokenStore.removeRefreshToken(refreshToken);
return R.ok();
}
从上诉方法中可以看出我是**tokenStore.removeAccessToken(accessToken);**出问题了。然后我进去源码看了下
public void removeAccessToken(String tokenValue) {
byte[] accessKey = serializeKey(ACCESS + tokenValue);
byte[] authKey = serializeKey(AUTH + tokenValue);
byte[] accessToRefreshKey = serializeKey(ACCESS_TO_REFRESH + tokenValue);
RedisConnection conn =