
目录
滑动窗口机制 (Sliding Window Mechanism)
[双Token机制/刷新令牌机制(Refresh Token)](#双Token机制/刷新令牌机制(Refresh Token))
用于实现Token续期的三大主流方案 :滑动窗口机制、**双Token/刷新令牌机制 (Refresh Token)**和 服务端自动续期。
滑动窗口机制 (Sliding Window Mechanism)
核心原理:
只要用户的Token在有效期内有活动,就会自动延长其Token过期时间
方案实现流程:

- 用户发起请求的时候携带Token,后端校验Token的有效性及剩余时间
- Token有效并且剩余时间低于阈值,后端生成新的Token(延长过期时间)
- 返回响应数据和新的Token给前端,前端使用新的Token替换旧的Token
- 若Token有效并且剩余时间高于阈值,返回正常响应数据,更换Token
Java代码实现:
java
@RestController
@Slf4j
public class AuthController {
/**
* Token过期时间(毫秒)
*/
private static final long ACCESS_TOKEN_EXPIRATION_TIME = 30 * 60 * 1000; // 30分钟
/**
* 续期阈值(毫秒)
*/
private static final long RENEWAL_THRESHOLD = 5 * 60 * 1000; // 5分钟内触发续期
/**
* 密钥
*/
private static final String SECRET = "PXrQbuCwXwOZzkML/Vm2S5rSwt1iybvmKtGDzVEu+Hc=";
/**
* 检查并续期Token
* 如果传入的Token即将过期(剩余时间小于等于续期阈值),则生成一个新的Token返回;
* 否则返回成功的响应,表示Token仍然有效。
*
* @param token 请求头中的Authorization字段,即原始Token
* @return Result<String> 响应结果,若需要续期则返回新的Token,否则返回空的成功结果
*/
@GetMapping("/api/token")
public Result<String> register(@RequestHeader("Authorization") String token) {
//1. 基础校验
if (token == null) {
return Result.error(ResultCode.UNAUTHORIZED); // 401 未授权
}
//2. 验证token
Algorithm algorithm = Algorithm.HMAC256(SECRET);
DecodedJWT decodedJWT = JWT.require(algorithm).build().verify(token);
Date expirationDate = decodedJWT.getExpiresAt();
long currentTime = System.currentTimeMillis();
long timeUntilExpiry = expirationDate.getTime() - currentTime;
// 判断是否需要续期:当剩余有效时间小于等于设定阈值时
if (timeUntilExpiry <= RENEWAL_THRESHOLD) {
// 生成新的Token
String newToken = generateToken(decodedJWT.getClaim("userId").asString());
return Result.success(newToken);
}
return Result.success();
}
/**
* 根据用户ID生成新的JWT Token
*
* @param userId 用户唯一标识
* @return 新生成的JWT Token字符串
*/
private String generateToken(String userId) {
Date now = new Date();
Date expirationDate = new Date(now.getTime() + ACCESS_TOKEN_EXPIRATION_TIME); // 过期时间为30分钟
return JWT.create()
.withIssuer("your_issuer")
.withIssuedAt(now)
.withExpiresAt(expirationDate)
.withClaim("userId", userId)
.sign(Algorithm.HMAC256(SECRET));
}
}
优点:
- **用户体验佳:**用户在持续操作的时候,完全感知不到登录状态的中断,体验非常流畅。
- **实现相对简单:**逻辑清晰,代码改动小,易于集成到现有系统中。
缺点:
- **安全性低:**如果用户的Token被窃取,攻击者只要持续发起请求,就可以让这个Token"永不过期",大大增加了被滥用的风险。
- **难以控制最大会话时长:**虽然每次都在续期,但很难限制一个会话的绝对最大生命周期(比如用户登录后必须24小时后强制重新登录)。
双Token机制/刷新令牌机制(Refresh Token)
此方案为业界最为主流、最推荐的方案,安全性高
核心原理:
此方案引入两种不同生命周期的Token
- Access Token (访问令牌):
-
- 生命周期短,一般为15分钟-2小时
- 每次请求API的时候都会带在
Authorization头中 - 包含用户部分身份信息,用于快速校验
- Refresh Token (刷新令牌):
-
- 生命周期长,一般7天-30天
- 不用于访问API,仅用于获取新的Access Token。
- 需要搭配服务端的Redis进行使用,用于校验其有效性。
方案实现流程:

- 用户发起登录请求,后端校验用户相关信息,若成功,后端生成Access Token和Refresh Token返回给前端,并且将Refresh Token存储到redis中用于后续的校验
- 用户再次请求服务端的时候,用户需要携带Access Token,若后端校验成功,那么成功响应或者继续处理;后端校验失败,返回401
- 用户端携带Refresh Token调用refresh接口,验证Refresh Token有效性及匹配性
- Refresh Token有效并且匹配,后端生成新的Access Token和新的Refresh Token,删除旧的Refresh Token,并且存储新的Refresh Token;后端执行成功,返回新的Access Token 和Refresh Token;若Refresh Token无效,则返回错误信息
- 后续用户端请求的时候使用新的Access Token重新发起之前失败的请求
Java代码实现:
- 注意:此处的代码是经过业务封装后的代码,大家关注业务逻辑即可,不必关注详细的实现细节
java
@RestController
@Slf4j
@RequiredArgsConstructor
@RequestMapping("/api/v1/auth")
public class AuthController {
private final JwtUtil jwtUtil; // jwt实现类
/**
* 刷新refreshToken
*
* @param refreshTokenRequest refreshToken
* @return refreshTokenResponse
*/
@GetMapping("/refreshToken")
public Result<RefreshTokenResponse> refreshToken(@RequestBody @Valid RefreshTokenRequest refreshTokenRequest) {
log.info("刷新token, refreshToken:{}",refreshTokenRequest.getRefreshToken());
if (refreshTokenRequest.getRefreshToken() == null || refreshTokenRequest.getRefreshToken().isEmpty()){
log.info("refreshToken为空或者不存在");
return Result.error(ResultCode.UNAUTHORIZED);
}
//1. 从refreshToken中获取用户名
String username = jwtUtil.extractUsernameFromToken(refreshTokenRequest.getRefreshToken());
if (username == null || username.isEmpty()){
log.info("refreshToken无效,此处无法提取出用户名");
return Result.error(ResultCode.TOKEN_INVALID);
}
//3. 校验refreshToken
if (!jwtUtil.validateRefreshToken(refreshTokenRequest.getRefreshToken())){
log.info("校验refreshToken失败:refreshToken{}", refreshTokenRequest.getRefreshToken());
return Result.error(ResultCode.UNAUTHORIZED);
}
//4. 重新生成token和refreshToken
String newToken = jwtUtil.generateToken(username);
String newRefreshToken = jwtUtil.generateRefreshToken(username);
log.info("刷新token成功,newToken:{}, newRefreshToken:{}", newToken, newRefreshToken);
return Result.success(RefreshTokenResponse.builder()
.token(newToken)
.refreshToken(newRefreshToken)
.build());
}
}
优点:
- **高安全性:**Access Token 寿命比较短,即使暴露危害相对较小
- 灵活性高: 可以精确控制
Access Token和Refresh Token的生命周期。
缺点:
- 实现复杂度高: 需要管理两种Token,需要额外的存储(如Redis)来维护
Refresh Token的状态。 - 增加网络请求: 当
Access Token过期时,需要先请求一次刷新接口,再重试原请求。
服务端自动续期
核心原理:
此方案和滑动窗口方案有类似之处,但是此方案更侧重于服务端主动管理和维护会话状态。并且此处的服务端自动续期是有状态的,依赖redis等存储来维护会话。然而滑动窗口方案是无状态的,只需要依赖Token本身即可。
方案实现流程:

Java代码实现:
优点:
- 控制力强:管理员可以完全掌控所有会话的状态。
- 安全性相对较高:可以实现强制下线、多端登录限制等功能。
- 可审计:所有会话活动都有记录。
缺点:
- 性能开销大:每次请求都需要查询和更新Redis,对数据库压力大。
- 系统复杂性高:需要维护会话存储和清理机制。
- 违背JWT无状态原则:JWT的设计初衷是无状态,此方案使其变为有状态,失去了部分优势。
总结对比
|-------|------------|----------------------|-------------|
| 特性 | 滑动窗口机制 | 双Token/刷新令牌 | 服务端自动续期 |
| 用户体验 | ⭐⭐⭐⭐⭐ (最佳) | ⭐⭐⭐⭐ (良好) | ⭐⭐⭐⭐ (良好) |
| 安全性 | ⭐⭐ (较低) | ⭐⭐⭐⭐⭐ (最高) | ⭐⭐⭐⭐ (高) |
| 实现复杂度 | ⭐⭐ (简单) | ⭐⭐⭐⭐ (复杂) | ⭐⭐⭐⭐⭐ (最复杂) |
| 服务器开销 | ⭐⭐⭐ (中等) | ⭐⭐⭐ (中等) | ⭐⭐ (高) |
| 是否无状态 | 是 | 否 (Refresh Token需存储) | 否 |
| 主流推荐度 | 低 | 高 | 中 |