refactor: redis + token 会话重构,添加用户访问和刷新令牌映射,支持单设备登录控制和刷新令牌时让历史的访问令牌时效
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
package com.youlai.boot.config.property;
|
package com.youlai.boot.config.property;
|
||||||
|
|
||||||
import jakarta.validation.constraints.Min;
|
import jakarta.validation.constraints.Min;
|
||||||
import jakarta.validation.constraints.NotEmpty;
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
|||||||
@@ -41,5 +41,6 @@ public class OnlineUser {
|
|||||||
/**
|
/**
|
||||||
* 角色权限集合
|
* 角色权限集合
|
||||||
*/
|
*/
|
||||||
private Set<String> authorities;
|
private Set<String> roles;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ public class JwtTokenManager implements TokenManager {
|
|||||||
* @param token JWT Token
|
* @param token JWT Token
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void blacklistToken(String token) {
|
public void invalidateToken(String token) {
|
||||||
if (token.startsWith(SecurityConstants.BEARER_TOKEN_PREFIX)) {
|
if (token.startsWith(SecurityConstants.BEARER_TOKEN_PREFIX)) {
|
||||||
token = token.substring(SecurityConstants.BEARER_TOKEN_PREFIX.length());
|
token = token.substring(SecurityConstants.BEARER_TOKEN_PREFIX.length());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.youlai.boot.core.security.token;
|
package com.youlai.boot.core.security.token;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
import cn.hutool.core.util.IdUtil;
|
import cn.hutool.core.util.IdUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.youlai.boot.common.constant.RedisConstants;
|
import com.youlai.boot.common.constant.RedisConstants;
|
||||||
@@ -33,12 +34,10 @@ import java.util.stream.Collectors;
|
|||||||
@Service
|
@Service
|
||||||
public class RedisTokenManager implements TokenManager {
|
public class RedisTokenManager implements TokenManager {
|
||||||
|
|
||||||
// 安全配置属性
|
|
||||||
private final SecurityProperties securityProperties;
|
private final SecurityProperties securityProperties;
|
||||||
private final RedisTemplate<String, Object> redisTemplate;
|
private final RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
public RedisTokenManager(SecurityProperties securityProperties,
|
public RedisTokenManager(SecurityProperties securityProperties, RedisTemplate<String, Object> redisTemplate) {
|
||||||
RedisTemplate<String, Object> redisTemplate) {
|
|
||||||
this.securityProperties = securityProperties;
|
this.securityProperties = securityProperties;
|
||||||
this.redisTemplate = redisTemplate;
|
this.redisTemplate = redisTemplate;
|
||||||
}
|
}
|
||||||
@@ -47,56 +46,35 @@ public class RedisTokenManager implements TokenManager {
|
|||||||
* 生成 Token
|
* 生成 Token
|
||||||
*
|
*
|
||||||
* @param authentication 用户认证信息
|
* @param authentication 用户认证信息
|
||||||
* @return
|
* @return 生成的 AuthenticationToken 对象
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public AuthenticationToken generateToken(Authentication authentication) {
|
public AuthenticationToken generateToken(Authentication authentication) {
|
||||||
SysUserDetails user = (SysUserDetails) authentication.getPrincipal();
|
SysUserDetails user = (SysUserDetails) authentication.getPrincipal();
|
||||||
int accessTtl = securityProperties.getSession().getAccessTokenTimeToLive();
|
|
||||||
int refreshTtl = securityProperties.getSession().getRefreshTokenTimeToLive();
|
|
||||||
|
|
||||||
// 生成随机令牌
|
|
||||||
String accessToken = IdUtil.fastSimpleUUID();
|
String accessToken = IdUtil.fastSimpleUUID();
|
||||||
String refreshToken = IdUtil.fastSimpleUUID();
|
String refreshToken = IdUtil.fastSimpleUUID();
|
||||||
|
|
||||||
// 构建用户在线信息(不包含密码)
|
// 构建用户在线信息
|
||||||
OnlineUser onlineUser = buildOnlineUser(user);
|
OnlineUser onlineUser = new OnlineUser(
|
||||||
|
user.getUserId(),
|
||||||
// 将访问令牌与刷新令牌与用户信息分别存入 Redis,并设置过期时间
|
user.getUsername(),
|
||||||
setRedisValue(
|
user.getDeptId(),
|
||||||
StrUtil.format(RedisConstants.Auth.ACCESS_TOKEN_USER, accessToken),
|
user.getDataScope(),
|
||||||
onlineUser,
|
user.getAuthorities().stream()
|
||||||
accessTtl
|
.map(GrantedAuthority::getAuthority)
|
||||||
|
.collect(Collectors.toSet())
|
||||||
);
|
);
|
||||||
|
|
||||||
setRedisValue(
|
// 存储访问令牌、刷新令牌和刷新令牌映射
|
||||||
StrUtil.format(RedisConstants.Auth.REFRESH_TOKEN_USER, refreshToken),
|
storeTokensInRedis(accessToken, refreshToken, onlineUser);
|
||||||
onlineUser,
|
|
||||||
refreshTtl
|
|
||||||
);
|
|
||||||
|
|
||||||
// 单设备登录控制,若不允许多设备登录,则通过用户ID映射保存当前最新的访问令牌
|
// 单设备登录控制
|
||||||
Boolean allowMultiLogin = securityProperties.getSession().getRedisToken().getAllowMultiLogin();
|
handleSingleDeviceLogin(user.getUserId(), accessToken);
|
||||||
if (!allowMultiLogin) {
|
|
||||||
Long userId = user.getUserId();
|
|
||||||
String userAccessTokenKey = StrUtil.format(RedisConstants.Auth.USER_ACCESS_TOKEN, userId);
|
|
||||||
// 获取当前用户已有的访问令牌
|
|
||||||
String oldAccessToken = (String) redisTemplate.opsForValue().get(userAccessTokenKey);
|
|
||||||
if (oldAccessToken != null) {
|
|
||||||
// 删除旧的访问令牌对应的用户信息缓存
|
|
||||||
redisTemplate.delete(StrUtil.format(RedisConstants.Auth.ACCESS_TOKEN_USER, oldAccessToken));
|
|
||||||
}
|
|
||||||
// 更新用户与访问令牌的映射
|
|
||||||
setRedisValue(userAccessTokenKey, accessToken, accessTtl);
|
|
||||||
}
|
|
||||||
// 同时存储用户与刷新令牌的映射,便于后续刷新和踢出旧会话
|
|
||||||
String userRefreshTokenKey = StrUtil.format(RedisConstants.Auth.USER_REFRESH_TOKEN, user.getUserId());
|
|
||||||
setRedisValue(userRefreshTokenKey, refreshToken, refreshTtl);
|
|
||||||
|
|
||||||
return AuthenticationToken.builder()
|
return AuthenticationToken.builder()
|
||||||
.accessToken(accessToken)
|
.accessToken(accessToken)
|
||||||
.refreshToken(refreshToken)
|
.refreshToken(refreshToken)
|
||||||
.expiresIn(accessTtl)
|
.expiresIn(securityProperties.getSession().getAccessTokenTimeToLive())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,29 +82,25 @@ public class RedisTokenManager implements TokenManager {
|
|||||||
* 根据 token 解析用户信息
|
* 根据 token 解析用户信息
|
||||||
*
|
*
|
||||||
* @param token JWT Token
|
* @param token JWT Token
|
||||||
* @return
|
* @return 构建的 Authentication 对象
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Authentication parseToken(String token) {
|
public Authentication parseToken(String token) {
|
||||||
// 根据访问令牌从 Redis 中获取在线用户信息
|
OnlineUser onlineUser = (OnlineUser) redisTemplate.opsForValue().get(formatTokenKey(token));
|
||||||
String tokenUserCacheKey = StrUtil.format(RedisConstants.Auth.ACCESS_TOKEN_USER, token);
|
|
||||||
OnlineUser onlineUser = (OnlineUser) redisTemplate.opsForValue().get(tokenUserCacheKey);
|
|
||||||
|
|
||||||
if (onlineUser == null) return null;
|
if (onlineUser == null) return null;
|
||||||
|
|
||||||
// 构建用户权限集合
|
// 构建用户权限集合
|
||||||
Set<SimpleGrantedAuthority> authorities = onlineUser.getAuthorities().stream()
|
Set<SimpleGrantedAuthority> authorities = null;
|
||||||
.map(SimpleGrantedAuthority::new)
|
|
||||||
.collect(Collectors.toSet());
|
Set<String> roles = onlineUser.getRoles();
|
||||||
|
if (CollectionUtil.isNotEmpty(roles)) {
|
||||||
|
authorities = roles.stream()
|
||||||
|
.map(SimpleGrantedAuthority::new)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
// 构建用户详情对象
|
// 构建用户详情对象
|
||||||
SysUserDetails userDetails = new SysUserDetails();
|
SysUserDetails userDetails = buildUserDetails(onlineUser, authorities);
|
||||||
userDetails.setUserId(onlineUser.getUserId());
|
|
||||||
userDetails.setUsername(onlineUser.getUsername());
|
|
||||||
userDetails.setDeptId(onlineUser.getDeptId());
|
|
||||||
userDetails.setDataScope(onlineUser.getDataScope());
|
|
||||||
userDetails.setAuthorities(authorities);
|
|
||||||
|
|
||||||
return new UsernamePasswordAuthenticationToken(userDetails, null, authorities);
|
return new UsernamePasswordAuthenticationToken(userDetails, null, authorities);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,51 +108,38 @@ public class RedisTokenManager implements TokenManager {
|
|||||||
* 校验 Token 是否有效
|
* 校验 Token 是否有效
|
||||||
*
|
*
|
||||||
* @param token 访问令牌
|
* @param token 访问令牌
|
||||||
* @return
|
* @return 是否有效
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean validateToken(String token) {
|
public boolean validateToken(String token) {
|
||||||
String tokenKey = StrUtil.format(RedisConstants.Auth.ACCESS_TOKEN_USER, token);
|
return redisTemplate.hasKey(formatTokenKey(token));
|
||||||
return redisTemplate.hasKey(tokenKey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 刷新令牌
|
* 刷新令牌
|
||||||
*
|
*
|
||||||
* @param refreshToken 刷新令牌
|
* @param refreshToken 刷新令牌
|
||||||
* @return
|
* @return 新生成的 AuthenticationToken 对象
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public AuthenticationToken refreshToken(String refreshToken) {
|
public AuthenticationToken refreshToken(String refreshToken) {
|
||||||
// 根据刷新令牌获取在线用户信息
|
OnlineUser onlineUser = (OnlineUser) redisTemplate.opsForValue().get(StrUtil.format(RedisConstants.Auth.REFRESH_TOKEN_USER, refreshToken));
|
||||||
String refreshKey = StrUtil.format(RedisConstants.Auth.REFRESH_TOKEN_USER, refreshToken);
|
|
||||||
OnlineUser onlineUser = (OnlineUser) redisTemplate.opsForValue().get(refreshKey);
|
|
||||||
|
|
||||||
if (onlineUser == null) {
|
if (onlineUser == null) {
|
||||||
throw new BusinessException(ResultCode.REFRESH_TOKEN_INVALID);
|
throw new BusinessException(ResultCode.REFRESH_TOKEN_INVALID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取当前用户的旧访问令牌(如果存在)
|
String oldAccessToken = (String) redisTemplate.opsForValue().get(StrUtil.format(RedisConstants.Auth.USER_ACCESS_TOKEN, onlineUser.getUserId()));
|
||||||
String userAccessKey = StrUtil.format(RedisConstants.Auth.USER_ACCESS_TOKEN, onlineUser.getUserId());
|
|
||||||
String oldAccessToken = (String) redisTemplate.opsForValue().get(userAccessKey);
|
// 删除旧的访问令牌记录
|
||||||
if (oldAccessToken != null) {
|
if (oldAccessToken != null) {
|
||||||
// 删除旧的访问令牌记录
|
redisTemplate.delete(formatTokenKey(oldAccessToken));
|
||||||
redisTemplate.delete(StrUtil.format(RedisConstants.Auth.ACCESS_TOKEN_USER, oldAccessToken));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成新访问令牌
|
// 生成新访问令牌并存储
|
||||||
String newAccessToken = IdUtil.fastSimpleUUID();
|
String newAccessToken = IdUtil.fastSimpleUUID();
|
||||||
|
storeAccessToken(newAccessToken, onlineUser);
|
||||||
|
|
||||||
int accessTtl = securityProperties.getSession().getAccessTokenTimeToLive();
|
int accessTtl = securityProperties.getSession().getAccessTokenTimeToLive();
|
||||||
redisTemplate.opsForValue().set(
|
|
||||||
StrUtil.format(RedisConstants.Auth.ACCESS_TOKEN_USER, newAccessToken),
|
|
||||||
onlineUser,
|
|
||||||
accessTtl,
|
|
||||||
TimeUnit.SECONDS
|
|
||||||
);
|
|
||||||
|
|
||||||
// 更新用户与访问令牌的映射(若单设备登录,则更新映射以踢出旧会话)
|
|
||||||
redisTemplate.opsForValue().set(userAccessKey, newAccessToken, accessTtl, TimeUnit.SECONDS);
|
|
||||||
|
|
||||||
return AuthenticationToken.builder()
|
return AuthenticationToken.builder()
|
||||||
.accessToken(newAccessToken)
|
.accessToken(newAccessToken)
|
||||||
.refreshToken(refreshToken)
|
.refreshToken(refreshToken)
|
||||||
@@ -187,24 +148,24 @@ public class RedisTokenManager implements TokenManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将 Token 加入黑名单
|
* 使访问令牌失效
|
||||||
*
|
*
|
||||||
* @param token 访问令牌
|
* @param token 访问令牌
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void blacklistToken(String token) {
|
public void invalidateToken(String token) {
|
||||||
// 删除访问令牌对应的在线用户信息缓存
|
OnlineUser onlineUser = (OnlineUser) redisTemplate.opsForValue().get(formatTokenKey(token));
|
||||||
String accessKey = StrUtil.format(RedisConstants.Auth.ACCESS_TOKEN_USER, token);
|
|
||||||
OnlineUser onlineUser = (OnlineUser) redisTemplate.opsForValue().get(accessKey);
|
|
||||||
|
|
||||||
if (onlineUser != null) {
|
if (onlineUser != null) {
|
||||||
Long userId = onlineUser.getUserId();
|
Long userId = onlineUser.getUserId();
|
||||||
|
// 1. 删除访问令牌相关
|
||||||
|
String userAccessKey = StrUtil.format(RedisConstants.Auth.USER_ACCESS_TOKEN, userId);
|
||||||
|
String accessToken = (String) redisTemplate.opsForValue().get(userAccessKey);
|
||||||
|
if (accessToken != null) {
|
||||||
|
redisTemplate.delete(formatTokenKey(accessToken));
|
||||||
|
redisTemplate.delete(userAccessKey);
|
||||||
|
}
|
||||||
|
|
||||||
// 删除访问令牌缓存和用户与访问令牌的映射
|
// 2. 删除刷新令牌相关
|
||||||
redisTemplate.delete(accessKey);
|
|
||||||
redisTemplate.delete(StrUtil.format(RedisConstants.Auth.USER_ACCESS_TOKEN, userId));
|
|
||||||
|
|
||||||
// 删除用户与刷新令牌的映射,以及刷新令牌对应的缓存
|
|
||||||
String userRefreshKey = StrUtil.format(RedisConstants.Auth.USER_REFRESH_TOKEN, userId);
|
String userRefreshKey = StrUtil.format(RedisConstants.Auth.USER_REFRESH_TOKEN, userId);
|
||||||
String refreshToken = (String) redisTemplate.opsForValue().get(userRefreshKey);
|
String refreshToken = (String) redisTemplate.opsForValue().get(userRefreshKey);
|
||||||
if (refreshToken != null) {
|
if (refreshToken != null) {
|
||||||
@@ -215,28 +176,91 @@ public class RedisTokenManager implements TokenManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建 OnlineUser 对象
|
* 将访问令牌和刷新令牌存储至 Redis
|
||||||
|
*
|
||||||
|
* @param accessToken 访问令牌
|
||||||
|
* @param refreshToken 刷新令牌
|
||||||
|
* @param onlineUser 在线用户信息
|
||||||
*/
|
*/
|
||||||
private OnlineUser buildOnlineUser(SysUserDetails user) {
|
private void storeTokensInRedis(String accessToken, String refreshToken, OnlineUser onlineUser) {
|
||||||
Long userId = user.getUserId();
|
// 访问令牌 -> 用户信息
|
||||||
Set<String> roles = user.getAuthorities().stream()
|
setRedisValue(formatTokenKey(accessToken), onlineUser, securityProperties.getSession().getAccessTokenTimeToLive());
|
||||||
.map(GrantedAuthority::getAuthority)
|
|
||||||
.collect(Collectors.toSet());
|
// 刷新令牌 -> 用户信息
|
||||||
return new OnlineUser(
|
String refreshTokenKey = StrUtil.format(RedisConstants.Auth.REFRESH_TOKEN_USER, refreshToken);
|
||||||
userId,
|
setRedisValue(refreshTokenKey, onlineUser, securityProperties.getSession().getRefreshTokenTimeToLive());
|
||||||
user.getUsername(),
|
|
||||||
user.getDeptId(),
|
// 用户ID -> 刷新令牌
|
||||||
user.getDataScope(),
|
setRedisValue(StrUtil.format(RedisConstants.Auth.USER_REFRESH_TOKEN, onlineUser.getUserId()),
|
||||||
roles
|
refreshToken,
|
||||||
);
|
securityProperties.getSession().getRefreshTokenTimeToLive());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将 Token 存储到 Redis
|
* 处理单设备登录控制
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @param accessToken 新生成的访问令牌
|
||||||
|
*/
|
||||||
|
private void handleSingleDeviceLogin(Long userId, String accessToken) {
|
||||||
|
Boolean allowMultiLogin = securityProperties.getSession().getRedisToken().getAllowMultiLogin();
|
||||||
|
String userAccessKey = StrUtil.format(RedisConstants.Auth.USER_ACCESS_TOKEN, userId);
|
||||||
|
// 单设备登录控制,删除旧的访问令牌
|
||||||
|
if (!allowMultiLogin) {
|
||||||
|
String oldAccessToken = (String) redisTemplate.opsForValue().get(userAccessKey);
|
||||||
|
if (oldAccessToken != null) {
|
||||||
|
redisTemplate.delete(formatTokenKey(oldAccessToken));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 存储访问令牌映射(用户ID -> 访问令牌),用于单设备登录控制删除旧的访问令牌和刷新令牌时删除旧令牌
|
||||||
|
setRedisValue(userAccessKey, accessToken, securityProperties.getSession().getAccessTokenTimeToLive());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 存储新的访问令牌
|
||||||
|
*
|
||||||
|
* @param newAccessToken 新访问令牌
|
||||||
|
* @param onlineUser 在线用户信息
|
||||||
|
*/
|
||||||
|
private void storeAccessToken(String newAccessToken, OnlineUser onlineUser) {
|
||||||
|
setRedisValue(StrUtil.format(RedisConstants.Auth.ACCESS_TOKEN_USER, newAccessToken), onlineUser, securityProperties.getSession().getAccessTokenTimeToLive());
|
||||||
|
String userAccessKey = StrUtil.format(RedisConstants.Auth.USER_ACCESS_TOKEN, onlineUser.getUserId());
|
||||||
|
setRedisValue(userAccessKey, newAccessToken, securityProperties.getSession().getAccessTokenTimeToLive());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建用户详情对象
|
||||||
|
*
|
||||||
|
* @param onlineUser 在线用户信息
|
||||||
|
* @param authorities 权限集合
|
||||||
|
* @return SysUserDetails 用户详情
|
||||||
|
*/
|
||||||
|
private SysUserDetails buildUserDetails(OnlineUser onlineUser, Set<SimpleGrantedAuthority> authorities) {
|
||||||
|
SysUserDetails userDetails = new SysUserDetails();
|
||||||
|
userDetails.setUserId(onlineUser.getUserId());
|
||||||
|
userDetails.setUsername(onlineUser.getUsername());
|
||||||
|
userDetails.setDeptId(onlineUser.getDeptId());
|
||||||
|
userDetails.setDataScope(onlineUser.getDataScope());
|
||||||
|
userDetails.setAuthorities(authorities);
|
||||||
|
return userDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化访问令牌的 Redis 键
|
||||||
|
*
|
||||||
|
* @param token 访问令牌
|
||||||
|
* @return 格式化后的 Redis 键
|
||||||
|
*/
|
||||||
|
private String formatTokenKey(String token) {
|
||||||
|
return StrUtil.format(RedisConstants.Auth.ACCESS_TOKEN_USER, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将值存储到 Redis
|
||||||
*
|
*
|
||||||
* @param key 键
|
* @param key 键
|
||||||
* @param value 值
|
* @param value 值
|
||||||
* @param ttl 过期时间(秒)
|
* @param ttl 过期时间(秒),-1表示永不过期
|
||||||
*/
|
*/
|
||||||
private void setRedisValue(String key, Object value, int ttl) {
|
private void setRedisValue(String key, Object value, int ttl) {
|
||||||
if (ttl != -1) {
|
if (ttl != -1) {
|
||||||
@@ -245,5 +269,4 @@ public class RedisTokenManager implements TokenManager {
|
|||||||
redisTemplate.opsForValue().set(key, value); // ttl=-1时永不过期
|
redisTemplate.opsForValue().set(key, value); // ttl=-1时永不过期
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ public interface TokenManager {
|
|||||||
*/
|
*/
|
||||||
Authentication parseToken(String token);
|
Authentication parseToken(String token);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 校验 Token 是否有效
|
* 校验 Token 是否有效
|
||||||
*
|
*
|
||||||
@@ -39,7 +38,6 @@ public interface TokenManager {
|
|||||||
*/
|
*/
|
||||||
boolean validateToken(String token);
|
boolean validateToken(String token);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 刷新 Token
|
* 刷新 Token
|
||||||
*
|
*
|
||||||
@@ -49,11 +47,11 @@ public interface TokenManager {
|
|||||||
AuthenticationToken refreshToken(String token);
|
AuthenticationToken refreshToken(String token);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将 Token 加入黑名单
|
* 令 Token 失效
|
||||||
*
|
*
|
||||||
* @param token JWT Token
|
* @param token JWT Token
|
||||||
*/
|
*/
|
||||||
default void blacklistToken(String token) {
|
default void invalidateToken(String token) {
|
||||||
// 默认实现可以是空的,或者抛出不支持的操作异常
|
// 默认实现可以是空的,或者抛出不支持的操作异常
|
||||||
// throw new UnsupportedOperationException("Not implemented");
|
// throw new UnsupportedOperationException("Not implemented");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ public class AuthServiceImpl implements AuthService {
|
|||||||
if (StrUtil.isNotBlank(token) && token.startsWith(SecurityConstants.BEARER_TOKEN_PREFIX )) {
|
if (StrUtil.isNotBlank(token) && token.startsWith(SecurityConstants.BEARER_TOKEN_PREFIX )) {
|
||||||
token = token.substring(SecurityConstants.BEARER_TOKEN_PREFIX .length());
|
token = token.substring(SecurityConstants.BEARER_TOKEN_PREFIX .length());
|
||||||
// 将JWT令牌加入黑名单
|
// 将JWT令牌加入黑名单
|
||||||
tokenManager.blacklistToken(token);
|
tokenManager.invalidateToken(token);
|
||||||
// 清除Security上下文
|
// 清除Security上下文
|
||||||
SecurityContextHolder.clearContext();
|
SecurityContextHolder.clearContext();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -408,7 +408,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
|
|||||||
if (result) {
|
if (result) {
|
||||||
// 加入黑名单,重新登录
|
// 加入黑名单,重新登录
|
||||||
String accessToken = SecurityUtils.getTokenFromRequest();
|
String accessToken = SecurityUtils.getTokenFromRequest();
|
||||||
tokenManager.blacklistToken(accessToken);
|
tokenManager.invalidateToken(accessToken);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user