新增个人中心修改密码、管理端重置密码后用户token失效能力

This commit is contained in:
gaoqr
2026-03-10 10:39:36 +08:00
parent 34887a9652
commit e73e976d68
3 changed files with 52 additions and 16 deletions
@@ -91,4 +91,10 @@ public interface OAuth2TokenService {
*/
PageResult<OAuth2AccessTokenDO> getAccessTokenPage(OAuth2AccessTokenPageReqVO reqVO);
/**
* 清除userId对应用户的token
* @param userId
*/
void kickOut(Long userId);
}
@@ -29,7 +29,6 @@ import org.springframework.transaction.annotation.Transactional;
import jakarta.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
@@ -240,9 +239,7 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
// 记录到 Redis 中
oauth2AccessTokenRedisDAO.set(accessTokenDO);
// 异步踢出其他token
CompletableFuture.runAsync(() -> {
kickOut(userId, currentToken);
}).exceptionally(e -> {
CompletableFuture.runAsync(() -> kickOut(userId, currentToken)).exceptionally(e -> {
log.error("[OAuth2TokenServiceImpl] redis 清空token失败, 用户id:{}, 异常:{}", userId, e);
return null;
});
@@ -256,22 +253,17 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
* @param currentToken
*/
public void kickOut(Long userId, String currentToken) {
List<String> matchKeys = new ArrayList<>();
Cursor<String> cursor = oauth2AccessTokenRedisDAO.scan();
while (cursor.hasNext()) {
matchKeys.add(cursor.next());
}
cursor.close();
if (CollUtil.isNotEmpty(matchKeys)) {
for (String key : matchKeys) {
// 获取key下的用户信息
OAuth2AccessTokenDO oAuth2AccessTokenDO = oauth2AccessTokenRedisDAO.getWithKey(key);
if (ObjectUtil.equal(userId, oAuth2AccessTokenDO.getUserId()) && !StringUtils.equals(currentToken, oAuth2AccessTokenDO.getAccessToken()) && Boolean.FALSE.equals(oAuth2AccessTokenDO.getIsSupAdmin())) {
// 用户id匹配、非当次登录token、非超管 -> 删除redis中的token缓存
oauth2AccessTokenRedisDAO.deleteWithKey(key);
}
String key = cursor.next();
// 获取key下的用户信息
OAuth2AccessTokenDO oAuth2AccessTokenDO = oauth2AccessTokenRedisDAO.getWithKey(key);
if (ObjectUtil.equal(userId, oAuth2AccessTokenDO.getUserId()) && !StringUtils.equals(currentToken, oAuth2AccessTokenDO.getAccessToken()) && Boolean.FALSE.equals(oAuth2AccessTokenDO.getIsSupAdmin())) {
// 用户id匹配、非当次登录token、非超管 -> 删除redis中的token缓存
oauth2AccessTokenRedisDAO.deleteWithKey(key);
}
}
cursor.close();
}
@@ -284,4 +276,18 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
return IdUtil.fastSimpleUUID();
}
@Override
public void kickOut(Long userId) {
Cursor<String> cursor = oauth2AccessTokenRedisDAO.scan();
while (cursor.hasNext()) {
String key = cursor.next();
// 获取key下的用户信息
OAuth2AccessTokenDO oAuth2AccessTokenDO = oauth2AccessTokenRedisDAO.getWithKey(key);
if (ObjectUtil.equal(userId, oAuth2AccessTokenDO.getUserId())) {
// 用户id匹配 -> 删除redis中的token缓存
oauth2AccessTokenRedisDAO.deleteWithKey(key);
}
}
cursor.close();
}
}
@@ -47,6 +47,7 @@ import com.cf.imes.module.system.enums.logger.LoginResultEnum;
import com.cf.imes.module.system.enums.sms.SmsSceneEnum;
import com.cf.imes.module.system.service.dept.DeptService;
import com.cf.imes.module.system.service.logger.LoginLogService;
import com.cf.imes.module.system.service.oauth2.OAuth2TokenService;
import com.cf.imes.module.system.service.organ.OrganService;
import com.cf.imes.module.system.service.permission.PermissionService;
import com.cf.imes.module.system.service.sms.SmsCodeService;
@@ -68,6 +69,7 @@ import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -119,6 +121,9 @@ public class AdminUserServiceImpl implements AdminUserService {
@Resource
private I18nUtils i18nUtils;
@Resource
private OAuth2TokenService oAuth2TokenService;
// 定义密码校验的正则表达式
private static final String LENGTH_PATTERN = ".{8,}";
private static final String UPPER_LETTER_PATTERN = ".*[A-Z].*";
@@ -261,6 +266,22 @@ public class AdminUserServiceImpl implements AdminUserService {
AdminUserDO updateObj = new AdminUserDO().setId(id);
updateObj.setPassword(encodePassword(reqVO.getNewPassword())); // 加密密码
userMapper.updateById(updateObj);
// 踢出登录
asyncKickOut(id);
}
/**
* 异步踢出登录
*
* @param userId
*/
private void asyncKickOut(Long userId) {
// 踢出登录
CompletableFuture.runAsync(() -> oAuth2TokenService.kickOut(userId)).exceptionally(e -> {
log.error("[AdminUserServiceImpl] redis 清空token失败, 用户id:{}, 异常:{}", userId, e);
return null;
});
}
@Override
@@ -287,6 +308,9 @@ public class AdminUserServiceImpl implements AdminUserService {
validatePassword(password);
updateObj.setPassword(encodePassword(password)); // 加密密码
userMapper.updateById(updateObj);
// 踢出登录
asyncKickOut(id);
}
@Override