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

Spring Boot中TokenExpiredException未被ControllerAdvice捕获如何解决

问题根因

  • Spring MVC 的@ControllerAdvice全局异常处理器仅能捕获从Controller层抛出的异常,而JWT校验的JWTValidarFilter属于Servlet过滤器,执行顺序远早于请求到达DispatcherServlet和Controller,过滤器中抛出的异常不会进入ControllerAdvice的处理逻辑,所以才会返回通用未处理错误。

解决方法

方法1:在Filter内直接处理异常

修改doFilterInternal方法,增加异常捕获逻辑,匹配到TokenExpiredException时直接构造响应返回,无需走全局异常流程:

@Override
protected void doFilterInternal(HttpServletRequest request, 
        HttpServletResponse response, FilterChain chain)
        throws IOException, ServletException {
    
    String atributo = request.getHeader(HEADER_ATRIBUTO);
            
    if(atributo == null) {
        chain.doFilter(request, response);
        return;
    }
    
    if(!atributo.startsWith(ATRIBUTO_PREFIXO)) {
        chain.doFilter(request, response);
        return;
    }
    
    String token = atributo.replace(ATRIBUTO_PREFIXO, "");
    try {
        UsernamePasswordAuthenticationToken authenticationToken = getAuthenticationToken(token);
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        chain.doFilter(request, response);
    } catch (TokenExpiredException e) {
        // 直接构造符合要求的响应
        response.setContentType("application/json;charset=utf-8");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        ObjectMapper mapper = new ObjectMapper();
        Map<String, Object> resMap = new HashMap<>();
        resMap.put("timestamp", new Date());
        resMap.put("message", e.getMessage());
        resMap.put("details", request.getRequestURI());
        response.getWriter().write(mapper.writeValueAsString(resMap));
    }
}

方法2:使用Spring Security原生认证异常处理入口

自定义AuthenticationEntryPoint统一处理所有Security层面的认证异常,可复用你全局异常的响应结构:

  1. 自定义异常处理器:
@Component
public class CustomAuthEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
        response.setContentType("application/json;charset=utf-8");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        ObjectMapper mapper = new ObjectMapper();
        Map<String, Object> resMap = new HashMap<>();
        resMap.put("timestamp", new Date());
        // 取出Filter中抛出的原始异常
        String errMsg = authException.getCause() != null ? authException.getCause().getMessage() : authException.getMessage();
        resMap.put("message", errMsg);
        resMap.put("details", request.getRequestURI());
        response.getWriter().write(mapper.writeValueAsString(resMap));
    }
}
  1. 在Spring Security配置类中注册该处理器:
@Autowired
private CustomAuthEntryPoint customAuthEntryPoint;

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable()
        .authorizeRequests()
        .anyRequest().authenticated()
        .and()
        // 配置自定义认证异常入口
        .exceptionHandling()
        .authenticationEntryPoint(customAuthEntryPoint)
        .and()
        .addFilter(new JWTValidarFilter(authenticationManager()));
        // 其余原有配置保持不变
}

修改完成后传入过期Token测试,即可返回你定义的401状态码和对应响应结构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 09:36:04