diff --git a/timeline-gateway-service/src/main/java/com/timeline/gateway/filter/AuthenticationFilter.java b/timeline-gateway-service/src/main/java/com/timeline/gateway/filter/AuthenticationFilter.java index b20d555..527217d 100644 --- a/timeline-gateway-service/src/main/java/com/timeline/gateway/filter/AuthenticationFilter.java +++ b/timeline-gateway-service/src/main/java/com/timeline/gateway/filter/AuthenticationFilter.java @@ -35,6 +35,7 @@ public class AuthenticationFilter implements GlobalFilter, Ordered { private RedisUtils redisUtils; private static final String TOKEN_BLACKLIST_PREFIX = "auth:token:blacklist:"; + private static final String TOKEN_ACTIVE_PREFIX = "auth:token:active:"; // 需要跳过认证的路径列表 private static final List WHITELIST_PATHS = Arrays.asList( @@ -55,33 +56,6 @@ public class AuthenticationFilter implements GlobalFilter, Ordered { return chain.filter(exchange); } - // WebSocket 连接需要 token,但不强制要求(允许通过,由下游服务处理) - if (path.startsWith("/user/ws")) { - String token = extractToken(request); - if (token != null && !token.isEmpty()) { - // 如果有 token,验证并传递用户信息 - if (jwtUtils.validateToken(token) && !isBlacklisted(token)) { - try { - Claims claims = jwtUtils.getClaimsFromToken(token); - if (claims != null && !jwtUtils.isTokenExpired(claims)) { - String userId = jwtUtils.getUserIdFromClaims(claims); - String username = jwtUtils.getUsernameFromClaims(claims); - ServerHttpRequest mutatedRequest = request.mutate() - .header("X-User-Id", userId) - .header("X-Username", username) - .build(); - ServerWebExchange mutatedExchange = exchange.mutate().request(mutatedRequest).build(); - return chain.filter(mutatedExchange); - } - } catch (Exception e) { - // token 验证失败,继续传递(由下游服务处理) - } - } - } - // 即使没有 token 也允许通过,由下游服务决定是否接受连接 - return chain.filter(exchange); - } - // 从请求头或查询参数中获取token String token = extractToken(request); @@ -104,6 +78,9 @@ public class AuthenticationFilter implements GlobalFilter, Ordered { return handleUnauthorized(exchange, "Token已过期"); } + // 刷新token有效期 + refreshTokenExpiration(token); + // 将用户信息添加到请求头中传递给下游服务 String userId = jwtUtils.getUserIdFromClaims(claims); String username = jwtUtils.getUsernameFromClaims(claims); @@ -142,7 +119,7 @@ public class AuthenticationFilter implements GlobalFilter, Ordered { String[] params = query.split("&"); for (String param : params) { if (param.startsWith("Authorization=")) { - return param.substring(21); + return param.substring("Authorization=".length()); } } } @@ -155,6 +132,29 @@ public class AuthenticationFilter implements GlobalFilter, Ordered { return Boolean.TRUE.equals(exists); } + // 添加刷新token有效期的方法 + private void refreshTokenExpiration(String token) { + try { + // 获取token的剩余有效时间 + long remainingSeconds = jwtUtils.getRemainingSeconds(token); + + // 获取总过期时间 + long totalExpiration = jwtUtils.getAccessExpirationSeconds() != null ? jwtUtils.getAccessExpirationSeconds() : 900L; + + // 定义一个阈值,当剩余时间少于总有效期的1/3时,刷新token在Redis中的活跃状态 + long refreshThreshold = totalExpiration / 3; + + if (remainingSeconds < refreshThreshold) { + // 在Redis中设置活跃token的记录,过期时间为完整的token有效期 + // 这样可以在用户持续活动时保持会话活跃 + redisUtils.expire(TOKEN_ACTIVE_PREFIX + token, totalExpiration); + log.debug("Token expiration refreshed for: {}, remaining seconds: {}", token, remainingSeconds); + } + } catch (Exception e) { + log.warn("Failed to refresh token expiration: {}", e.getMessage()); + } + } + @SuppressWarnings("null") private Mono handleUnauthorized(ServerWebExchange exchange, String message) { ServerHttpResponse response = exchange.getResponse(); diff --git a/timeline-gateway-service/src/main/java/com/timeline/gateway/utils/JwtUtils.java b/timeline-gateway-service/src/main/java/com/timeline/gateway/utils/JwtUtils.java index 8f5e11d..5b64315 100644 --- a/timeline-gateway-service/src/main/java/com/timeline/gateway/utils/JwtUtils.java +++ b/timeline-gateway-service/src/main/java/com/timeline/gateway/utils/JwtUtils.java @@ -16,6 +16,9 @@ public class JwtUtils { @Value("${jwt.secret:timelineSecretKey}") private String secret; + @Value("${jwt.access-expiration:900}") + private Long accessExpirationSeconds; + private byte[] secretBytes() { return secret.getBytes(StandardCharsets.UTF_8); } @@ -64,4 +67,33 @@ public class JwtUtils { } return claims.getSubject(); } -} + + // 添加获取过期时间的方法 + public Date getExpirationDateFromToken(String token) { + Claims claims = getClaimsFromToken(token); + if (claims != null) { + return claims.getExpiration(); + } + return null; + } + + // 添加获取剩余有效期的方法 + public long getRemainingSeconds(String token) { + try { + Date exp = getExpirationDateFromToken(token); + if (exp == null) { + return 0L; + } + long diff = exp.getTime() - System.currentTimeMillis(); + // 直接计算秒数而不是使用TimeUnit + return diff > 0 ? diff / 1000 : 0L; + } catch (Exception e) { + return 0L; + } + } + + // 添加获取访问令牌过期秒数的方法 + public Long getAccessExpirationSeconds() { + return accessExpirationSeconds; + } +} \ No newline at end of file