✨ feat(system): 添加令牌清理定时任务

This commit is contained in:
preschooler
2026-05-05 11:24:21 +08:00
parent 56772d08d8
commit 6c7282ff27
5 changed files with 113 additions and 0 deletions
@@ -6,7 +6,9 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.time.LocalDateTime;
import java.util.List;
@@ -37,4 +39,14 @@ public interface OAuth2AccessTokenMapper extends BaseMapperX<OAuth2AccessTokenDO
OAuth2AccessTokenDO::getUserType, userType);
}
/**
* 物理删除指定过期时间之前的访问令牌
*
* @param expiresTime 最大时间
* @param limit 删除条数,防止一次删除太多
* @return 删除条数
*/
@Delete("DELETE FROM system_oauth2_access_token WHERE expires_time < #{expiresTime} LIMIT #{limit}")
Integer deleteByExpiresTimeLt(@Param("expiresTime") LocalDateTime expiresTime, @Param("limit") Integer limit);
}
@@ -4,7 +4,11 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2RefreshTokenDO;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.time.LocalDateTime;
@Mapper
public interface OAuth2RefreshTokenMapper extends BaseMapperX<OAuth2RefreshTokenDO> {
@@ -19,4 +23,13 @@ public interface OAuth2RefreshTokenMapper extends BaseMapperX<OAuth2RefreshToken
return selectOne(OAuth2RefreshTokenDO::getRefreshToken, refreshToken);
}
/**
* 物理删除指定过期时间之前的刷新令牌
*
* @param expiresTime 最大时间
* @param limit 删除条数,防止一次删除太多
* @return 删除条数
*/
@Delete("DELETE FROM system_oauth2_refresh_token WHERE expires_time < #{expiresTime} LIMIT #{limit}")
Integer deleteByExpiresTimeLt(@Param("expiresTime") LocalDateTime expiresTime, @Param("limit") Integer limit);
}
@@ -0,0 +1,42 @@
package cn.iocoder.yudao.module.system.job.token;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* 物理删除过期 N 天的令牌的 Job
*
* @author preschooler
*/
@Component
@Slf4j
public class TokenCleanJob implements JobHandler {
@Resource
private OAuth2TokenService oauth2TokenService;
/**
* 清理过期(14)天的令牌
*/
private static final Integer JOB_CLEAN_RETAIN_DAY = 14;
/**
* 每次删除间隔的条数,如果值太高可能会造成数据库的压力过大
*/
private static final Integer DELETE_LIMIT = 100;
@Override
@TenantIgnore
public String execute(String param) {
Integer refreshCount = oauth2TokenService.cleanRefreshToken(JOB_CLEAN_RETAIN_DAY, DELETE_LIMIT);
log.info("[execute][定时执行清理刷新令牌数量 ({}) 个]", refreshCount);
Integer accessCount = oauth2TokenService.cleanAccessToken(JOB_CLEAN_RETAIN_DAY, DELETE_LIMIT);
log.info("[execute][定时执行清理访问令牌数量 ({}) 个]", accessCount);
return String.format("定时执行清理刷新令牌数量 %s 个,访问令牌数量 %s 个", refreshCount, accessCount);
}
}
@@ -88,4 +88,19 @@ public interface OAuth2TokenService {
*/
PageResult<OAuth2AccessTokenDO> getAccessTokenPage(OAuth2AccessTokenPageReqVO reqVO);
/**
* 清理过期 exceedDay 天的刷新令牌
*
* @param exceedDay 过期多少天就进行清理
* @param deleteLimit 清理的间隔条数
*/
Integer cleanRefreshToken(Integer exceedDay, Integer deleteLimit);
/**
* 清理过期 exceedDay 天的访问令牌
*
* @param exceedDay 过期多少天就进行清理
* @param deleteLimit 清理的间隔条数
*/
Integer cleanAccessToken(Integer exceedDay, Integer deleteLimit);
}
@@ -243,4 +243,35 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
return IdUtil.fastSimpleUUID();
}
@Override
public Integer cleanRefreshToken(Integer exceedDay, Integer deleteLimit) {
int count = 0;
LocalDateTime expireDate = LocalDateTime.now().minusDays(exceedDay);
// 循环删除,直到没有满足条件的数据
for (int i = 0; i < Short.MAX_VALUE; i++) {
int deleteCount = oauth2RefreshTokenMapper.deleteByExpiresTimeLt(expireDate, deleteLimit);
count += deleteCount;
// 达到删除预期条数,说明到底了
if (deleteCount < deleteLimit) {
break;
}
}
return count;
}
@Override
public Integer cleanAccessToken(Integer exceedDay, Integer deleteLimit) {
int count = 0;
LocalDateTime expireDate = LocalDateTime.now().minusDays(exceedDay);
// 循环删除,直到没有满足条件的数据
for (int i = 0; i < Short.MAX_VALUE; i++) {
int deleteCount = oauth2AccessTokenMapper.deleteByExpiresTimeLt(expireDate, deleteLimit);
count += deleteCount;
// 达到删除预期条数,说明到底了
if (deleteCount < deleteLimit) {
break;
}
}
return count;
}
}