前言:在开发过程中,有块业务场景是需要退出用户登录,但是security框架中,认证登录和退出登录的方法都被限制的很死,没有可以直接调用的方法块,基于我使用的配置基于redis的认证,需要手动实现用户退出登录。
解决方案:Security框架有提供一个TokenStore的接口,其中有直接操作token的方法,但是比较原子化,需要自己写一个通用退出登录方法使用。
代码如下:
public void logout(Integer tenantId , String username){
if(StringUtils.isBlank(clientStr)) {
return;
} //强制退出用户
Collection<OAuth2AccessToken> tokensByClientIdAndUserName = tokenStore.findTokensByClientIdAndUserName(clientStr, username);
if(CollectionUtils.isEmpty(tokensByClientIdAndUserName)) { return;
}
for (OAuth2AccessToken auth2AccessToken : tokensByClientIdAndUserName) {
OAuth2Authentication auth2Authentication = tokenStore.readAuthentication(auth2AccessToken.getValue());
OAuth2AccessToken accessToken = tokenStore.readAccessToken(auth2AccessToken.getValue());
// 清空用户信息
if(Objects.nonNull(auth2Authentication)) { cacheManager.getCache(CacheConstants.USER_DETAILS)
.evict(auth2Authentication.getName());
} if(Objects.isNull(accessToken)) {
continue;
} // 清空access token
tokenStore.removeAccessToken(accessToken);
// 清空 refresh token
OAuth2RefreshToken refreshToken = accessToken.getRefreshToken();
if(refreshToken == null) { continue;
} tokenStore.removeRefreshToken(refreshToken);
}}
但是这个强制退出登录有个问题,生效时间只能在使用token下一次访问接口是,那么如果当前调用链路有其他使用接口得地方,还需要退出securiry的当前认证对象。
我的解决方案很简单,直接把当前认证对象置空即可。
SecurityContextHolder.getContext().setAuthentication(null);