You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring MVC中JWT令牌失效实现登出功能的技术咨询

嘿,刚好碰到过类似的问题!JWT本身是无状态、自包含的特性,导致没法直接让已签发的令牌“作废”,得借助额外机制来实现登出功能。结合你用Spring MVC搭后端、Angular 5做前端的栈,给你几个落地性强的方案:

方案1:令牌黑名单机制(生产环境最常用)

核心思路是维护一个已失效令牌的列表,在每次验证JWT前先检查令牌是否在黑名单中。步骤如下:

  • 1. 选择黑名单存储:推荐用Redis(自带过期时间,自动清理失效条目);如果是单实例测试环境,也可以用ConcurrentHashMap临时替代(生产环境禁止用内存存储,多实例会导致黑名单不一致)
  • 2. 实现登出接口:前端调用登出接口时,将当前令牌存入黑名单,并设置过期时间与令牌自身的exp(过期时间)一致
  • 3. 改造JWT验证逻辑:在拦截器/过滤器中,先检查令牌是否在黑名单,再执行常规的JWT签名验证

后端代码片段(Spring MVC)

登出接口

@RestController
@RequestMapping("/api/auth")
public class AuthController {
    private static final Logger logger = LoggerFactory.getLogger(AuthController.class);
    
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private JwtUtil jwtUtil; // 你已编写的JWT工具类

    @PostMapping("/logout")
    public ResponseEntity<String> logout(@RequestHeader("Authorization") String authHeader) {
        // 提取Bearer令牌
        String token = authHeader.replace("Bearer ", "").trim();
        // 获取令牌的过期时间
        Date expireDate = jwtUtil.extractExpiration(token);
        long expireMillis = expireDate.getTime() - System.currentTimeMillis();

        // 将令牌存入黑名单,设置过期时间与令牌一致
        redisTemplate.opsForValue()
                .set("JWT_BLACKLIST:" + token, "invalid", expireMillis, TimeUnit.MILLISECONDS);
        
        logger.info("Token {} added to blacklist", token);
        return ResponseEntity.ok("Logout successful");
    }
}

JWT验证过滤器改造

public class JwtAuthFilter extends OncePerRequestFilter {
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private JwtUtil jwtUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest request, 
                                    HttpServletResponse response, 
                                    FilterChain filterChain) throws ServletException, IOException {
        String token = extractToken(request);
        if (token != null) {
            // 先检查黑名单
            if (redisTemplate.hasKey("JWT_BLACKLIST:" + token)) {
                response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token has been invalidated");
                return;
            }
            // 执行原有JWT验证逻辑
            if (jwtUtil.validateToken(token)) {
                // 将用户信息存入SecurityContext(如果用Spring Security的话)
                // ...你的原有验证逻辑
            }
        }
        filterChain.doFilter(request, response);
    }

    private String extractToken(HttpServletRequest request) {
        String authHeader = request.getHeader("Authorization");
        return authHeader != null && authHeader.startsWith("Bearer ") 
                ? authHeader.substring(7) 
                : null;
    }
}

前端代码片段(Angular 5)

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';

@Injectable()
export class AuthService {
  private apiUrl = '/api/auth';

  constructor(private http: HttpClient) {}

  logout(): Promise<void> {
    const token = localStorage.getItem('jwtToken');
    return this.http.post(`${this.apiUrl}/logout`, {}, {
      headers: { 'Authorization': `Bearer ${token}` }
    }).toPromise().then(() => {
      // 清除本地存储的令牌
      localStorage.removeItem('jwtToken');
      // 跳转到登录页
      window.location.href = '/login';
    }).catch(err => {
      console.error('Logout failed:', err);
      // 即使后端出错,也清除本地令牌
      localStorage.removeItem('jwtToken');
      throw err;
    });
  }
}
方案2:短有效期访问令牌+刷新令牌

如果不想维护大量黑名单条目,可以把访问令牌(Access Token)的有效期设得很短(比如15分钟),同时签发一个刷新令牌(Refresh Token)(有效期几小时/几天)。登出时:

  • 前端清除本地的访问令牌和刷新令牌
  • 后端将刷新令牌加入黑名单(因为刷新令牌有效期长,黑名单条目少)

这个方案的优势是黑名单的存储压力小,适合用户登录状态持续时间较长的场景。代码逻辑和方案1类似,只是登出时处理的是刷新令牌。

方案3:前端主动清除令牌(仅前端层面)

这是最简单但安全性最低的方案:前端直接清除本地存储的JWT令牌,不再携带令牌请求接口。但后端的令牌仍然有效,恶意用户如果拿到令牌仍可继续访问。适合低安全要求的测试场景:

logout(): void {
  localStorage.removeItem('jwtToken');
  sessionStorage.removeItem('jwtToken');
  window.location.href = '/login';
}

总结

生产环境优先选方案1(令牌黑名单)或方案2(刷新令牌),根据你的架构和安全需求决定。如果是分布式系统,一定要用Redis这类分布式存储来维护黑名单,避免多实例数据不一致的问题。

内容的提问来源于stack exchange,提问作者faserx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:35:09