Spring Boot 3.0.0抛出异常时HttpStatus处理异常问题
Spring Boot 3.0.0自定义认证过滤器下异常状态码被覆盖为403的问题解决
问题根源
Spring Security 6.0(对应Spring Boot 3.0.0-RC2及正式版)调整了ExceptionTranslationFilter的逻辑:当请求处理抛出异常时,会重新校验当前请求的认证状态。若自定义认证过滤器未正确将Authentication对象存入SecurityContextHolder的线程安全上下文,异常处理阶段会判定用户未认证,从而返回配置的未认证状态码(默认403)。
解决方案
修正自定义认证过滤器的上下文设置逻辑
确保认证信息存入独立的SecurityContext,避免线程安全问题,同时保证异常处理阶段能读取到有效认证信息:@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { Authentication auth = new UsernamePasswordAuthenticationToken( "test-user", null, Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")) ); // 创建新上下文并设置认证信息 SecurityContext context = SecurityContextHolder.createEmptyContext(); context.setAuthentication(auth); SecurityContextHolder.setContext(context); try { filterChain.doFilter(request, response); } finally { // 请求结束后清理上下文,避免线程污染 SecurityContextHolder.clearContext(); } }确保自定义过滤器执行顺序正确
把自定义认证过滤器放在UsernamePasswordAuthenticationFilter之前,保证认证逻辑在异常处理前执行:@Override protected void configure(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth.anyRequest().authenticated()) .addFilterBefore(new CustomAuthFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class); }验证异常处理器逻辑
若使用全局异常处理器,确保它能正确捕获异常并返回指定状态码,且不干扰Security上下文:@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(HttpResponseException.class) public ResponseEntity<String> handleHttpResponseException(HttpResponseException ex) { return ResponseEntity.status(ex.getStatus()).body(ex.getMessage()); } }
补充说明
该问题仅出现在Spring Boot 3.0.0-RC2及正式版,是Spring Security 6.0对异常处理流程的合规性调整导致。在2.7.x及3.0.0-RC1中,异常处理阶段不会重新校验认证状态,因此未暴露该问题。
内容的提问来源于stack exchange,提问作者Gobanit
相关产品推荐
相关产品推荐

