为何Spring中抛出ResponseStatusException(400)却返回403状态码?
问题:抛出ResponseStatusException后返回403而非设置的400状态码
我有一个Spring Boot应用,安全配置如下:
@Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() .headers().frameOptions().sameOrigin().and() .addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class) .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() .antMatchers("/api/authenticate/**", "/h2-console/**").permitAll() .anyRequest().authenticated(); }
在业务代码中,我抛出了ResponseStatusException:
if (existingTenant.isPresent()) { throw new ResponseStatusException( HttpStatusCode.valueOf(400), "Tenant with name " + tenant.name() + " already exists"); }
但API实际返回的是403状态码:
* Mark bundle as not supporting multiuse < HTTP/1.1 403 < X-Content-Type-Options: nosniff < X-XSS-Protection: 1; mode=block < Cache-Control: no-cache, no-store, max-age=0, must-revalidate < Pragma: no-cache < Expires: 0 < X-Frame-Options: SAMEORIGIN < Content-Length: 0 < Date: Sat, 13 Aug 2022 19:26:27 GMT < * Connection #0 to host localhost left intact
仅看到如下日志:
2022-08-13T12:32:09.260-07:00 WARN 79360 --- [nio-8080-exec-6] .w.s.m.a.ResponseStatusExceptionResolver : Resolved [org.springframework.web.server.ResponseStatusException: 400 BAD_REQUEST "Tenant with name tenant1 already exists"]
为何响应没有返回我在异常中设置的400状态码?
解答
从日志能看到ResponseStatusExceptionResolver已经成功把异常解析为400状态码,但实际返回403,说明异常解析完成后,有后续组件(大概率是你配置的JWT过滤器jwtTokenFilter)修改了响应状态码,或者过滤器的异常处理逻辑导致Spring Security返回了403。
排查方向及解决方案:
检查JWT过滤器的实现
- 查看
jwtTokenFilter的doFilter方法,是否在调用chain.doFilter(request, response)后强制覆盖了响应状态码;或者捕获异常时没有重新抛出,而是自行设置了403状态码。 - 正确的过滤器实现要保证异常能被后续异常解析器处理,示例如下:
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { try { // 执行JWT校验逻辑 chain.doFilter(request, response); // 必须调用此方法,让请求继续流转 } catch (Exception e) { // 不要自行设置状态码,直接抛出异常交给Spring的异常处理器处理 throw e; } }
- 查看
确认请求是否通过认证
- 虽然日志显示异常被解析,但如果JWT过滤器在业务代码抛出异常前就判定请求未通过认证,Spring Security会直接返回403,此时业务代码的异常只是被记录,实际响应已被Security覆盖。可以在过滤器中添加日志,确认认证是否成功。
检查Spring Security异常处理器配置
- 若自定义了
AccessDeniedHandler或AuthenticationEntryPoint,确认这些处理器没有错误地将所有异常统一处理为403状态码。
- 若自定义了
内容的提问来源于stack exchange,提问作者Kevin
相关产品推荐
相关产品推荐

