新增个人中心修改密码、管理端重置密码后用户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); 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 jakarta.annotation.Resource;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@@ -240,9 +239,7 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
// 记录到 Redis 中 // 记录到 Redis 中
oauth2AccessTokenRedisDAO.set(accessTokenDO); oauth2AccessTokenRedisDAO.set(accessTokenDO);
// 异步踢出其他token // 异步踢出其他token
CompletableFuture.runAsync(() -> { CompletableFuture.runAsync(() -> kickOut(userId, currentToken)).exceptionally(e -> {
kickOut(userId, currentToken);
}).exceptionally(e -> {
log.error("[OAuth2TokenServiceImpl] redis 清空token失败, 用户id:{}, 异常:{}", userId, e); log.error("[OAuth2TokenServiceImpl] redis 清空token失败, 用户id:{}, 异常:{}", userId, e);
return null; return null;
}); });
@@ -256,14 +253,9 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
* @param currentToken * @param currentToken
*/ */
public void kickOut(Long userId, String currentToken) { public void kickOut(Long userId, String currentToken) {
List<String> matchKeys = new ArrayList<>();
Cursor<String> cursor = oauth2AccessTokenRedisDAO.scan(); Cursor<String> cursor = oauth2AccessTokenRedisDAO.scan();
while (cursor.hasNext()) { while (cursor.hasNext()) {
matchKeys.add(cursor.next()); String key = cursor.next();
}
cursor.close();
if (CollUtil.isNotEmpty(matchKeys)) {
for (String key : matchKeys) {
// 获取key下的用户信息 // 获取key下的用户信息
OAuth2AccessTokenDO oAuth2AccessTokenDO = oauth2AccessTokenRedisDAO.getWithKey(key); OAuth2AccessTokenDO oAuth2AccessTokenDO = oauth2AccessTokenRedisDAO.getWithKey(key);
if (ObjectUtil.equal(userId, oAuth2AccessTokenDO.getUserId()) && !StringUtils.equals(currentToken, oAuth2AccessTokenDO.getAccessToken()) && Boolean.FALSE.equals(oAuth2AccessTokenDO.getIsSupAdmin())) { if (ObjectUtil.equal(userId, oAuth2AccessTokenDO.getUserId()) && !StringUtils.equals(currentToken, oAuth2AccessTokenDO.getAccessToken()) && Boolean.FALSE.equals(oAuth2AccessTokenDO.getIsSupAdmin())) {
@@ -271,7 +263,7 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
oauth2AccessTokenRedisDAO.deleteWithKey(key); oauth2AccessTokenRedisDAO.deleteWithKey(key);
} }
} }
} cursor.close();
} }
@@ -284,4 +276,18 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
return IdUtil.fastSimpleUUID(); 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.enums.sms.SmsSceneEnum;
import com.cf.imes.module.system.service.dept.DeptService; 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.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.organ.OrganService;
import com.cf.imes.module.system.service.permission.PermissionService; import com.cf.imes.module.system.service.permission.PermissionService;
import com.cf.imes.module.system.service.sms.SmsCodeService; import com.cf.imes.module.system.service.sms.SmsCodeService;
@@ -68,6 +69,7 @@ import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.LocalTime; import java.time.LocalTime;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -119,6 +121,9 @@ public class AdminUserServiceImpl implements AdminUserService {
@Resource @Resource
private I18nUtils i18nUtils; private I18nUtils i18nUtils;
@Resource
private OAuth2TokenService oAuth2TokenService;
// 定义密码校验的正则表达式 // 定义密码校验的正则表达式
private static final String LENGTH_PATTERN = ".{8,}"; private static final String LENGTH_PATTERN = ".{8,}";
private static final String UPPER_LETTER_PATTERN = ".*[A-Z].*"; private static final String UPPER_LETTER_PATTERN = ".*[A-Z].*";
@@ -261,6 +266,22 @@ public class AdminUserServiceImpl implements AdminUserService {
AdminUserDO updateObj = new AdminUserDO().setId(id); AdminUserDO updateObj = new AdminUserDO().setId(id);
updateObj.setPassword(encodePassword(reqVO.getNewPassword())); // 加密密码 updateObj.setPassword(encodePassword(reqVO.getNewPassword())); // 加密密码
userMapper.updateById(updateObj); 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 @Override
@@ -287,6 +308,9 @@ public class AdminUserServiceImpl implements AdminUserService {
validatePassword(password); validatePassword(password);
updateObj.setPassword(encodePassword(password)); // 加密密码 updateObj.setPassword(encodePassword(password)); // 加密密码
userMapper.updateById(updateObj); userMapper.updateById(updateObj);
// 踢出登录
asyncKickOut(id);
} }
@Override @Override