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

Spring Boot微服务InvalidTokenException返回500错误如何处理?

问题根因

InvalidTokenException是在Spring Security过滤器链执行阶段抛出的,请求还未进入Controller层,因此默认的@ControllerAdvice全局异常处理器无法捕获该异常,最终会被BasicErrorController处理返回500状态码。

解决方案

以下提供两种常用的可落地处理方案:

方案1:配置资源服务器专属异常处理器(推荐)

Spring Security的OAuth2资源服务器本身提供了认证异常、权限异常的处理扩展点,直接配置即可覆盖这类场景:

  1. 自定义认证入口点,处理所有认证相关异常:
@Component
public class CustomAuthenticationEntryPoint 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);
        // 判断根异常是否为无效令牌异常
        if (authException.getCause() instanceof InvalidTokenException) {
            response.getWriter().write("{\"code\":401,\"message\":\"无效的访问令牌,请重新登录\"}");
            return;
        }
        response.getWriter().write("{\"code\":401,\"message\":\"请先完成身份认证\"}");
    }
}
  1. 自定义权限拒绝处理器,处理权限不足场景:
@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
        response.setContentType("application/json;charset=utf-8");
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        response.getWriter().write("{\"code\":403,\"message\":\"权限不足,无法访问当前资源\"}");
    }
}
  1. 将两个处理器注入到安全配置中(Spring Boot 2.7+ 推荐使用SecurityFilterChain配置):
@Configuration
public class ResourceSecurityConfig {
    @Autowired
    private CustomAuthenticationEntryPoint authenticationEntryPoint;
    @Autowired
    private CustomAccessDeniedHandler accessDeniedHandler;

    @Bean
    public SecurityFilterChain resourceSecurityChain(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // 放行获取令牌的接口
                .antMatchers("/oauth/token").permitAll()
                .anyRequest().authenticated()
                .and()
                .exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPoint)
                .accessDeniedHandler(accessDeniedHandler)
                .and()
                .oauth2ResourceServer().jwt(); // 按你实际的token校验方式配置即可
        return http.build();
    }
}

如果使用的是旧版本的ResourceServerConfigurerAdapter,直接在configure(HttpSecurity http)方法中添加上述exceptionHandling配置即可。

方案2:全局异常过滤器兜底

如果需要统一处理所有过滤器层抛出的异常,可以新增一个优先级最高的异常过滤器,放在Spring Security过滤器链之前捕获所有异常:

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class GlobalSecurityExceptionFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException {
        try {
            chain.doFilter(request, response);
        } catch (Exception e) {
            HttpServletResponse resp = (HttpServletResponse) response;
            resp.setContentType("application/json;charset=utf-8");
            // 匹配无效令牌异常
            if (e instanceof InvalidTokenException 
                || (e instanceof AuthenticationException && e.getCause() instanceof InvalidTokenException)) {
                resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                resp.getWriter().write("{\"code\":401,\"message\":\"无效的访问令牌,请重新登录\"}");
                return;
            }
            // 其他异常统一处理逻辑可自行扩展
            resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            resp.getWriter().write("{\"code\":500,\"message\":\"服务器内部错误\"}");
        }
    }
}

注意事项

异常抛出时通常会被Spring Security做一层包装,判断类型时优先检查根异常getCause()即可避免漏匹配的情况。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 06:15:04