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

SpringBoot自定义Logout控制器返回204无内容问题求助

自定义登出控制器返回204 No Content问题解决

问题描述

我编写了自定义登出控制器处理用户登出逻辑,但用PostMan测试时,接口始终返回204 No Content,而非预期的200 OK并携带signed-out响应内容。

初始代码:

@RestController
@RequestMapping("/auth/api/access/login/")
public class SignoutController implements LogoutHandler
{         
 @GetMapping("signout")
 public ResponseEntity<String> viewlogout(HttpServletRequest request, HttpServletResponse response)
 {    
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 
    this.logout(request, response, authentication); 
    return new ResponseEntity<>("signed-out", HttpStatus.OK);
 }  

@Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
{        
    if (authentication != null)
    {    
       new SecurityContextLogoutHandler().logout(request, response, authentication);
    }     
  }
}

修改后(移除HttpServletResponse参数)问题仍未解决:

@RestController
@RequestMapping("/auth/api/access/login/")
public class SignoutController implements LogoutHandler
{         
 @GetMapping("signout")
 public ResponseEntity<String> viewlogout(HttpServletRequest request)
 {    
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 
    this.logout(request, null, authentication); 
    return new ResponseEntity<>("signed-out", HttpStatus.OK);
 }  

@Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
{        
    if (authentication != null)
    {    
       new SecurityContextLogoutHandler().logout(request, response, authentication);
    }     
 }
}

问题原因

SecurityContextLogoutHandler的logout方法会直接修改HttpServletResponse的状态码为204 NO_CONTENT,覆盖控制器中ResponseEntity设置的响应状态和内容。即使传入null作为response参数,Spring Security的默认登出过滤器可能仍会介入请求处理,导致响应被强制修改。

解决方案

方案1:手动处理登出逻辑

直接清理安全上下文并使会话失效,避免依赖SecurityContextLogoutHandler修改响应:

@RestController
@RequestMapping("/auth/api/access/login/")
public class SignoutController {         
    @GetMapping("signout")
    public ResponseEntity<String> viewlogout(HttpServletRequest request) {    
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 
        if (authentication != null) {
            // 清理安全上下文
            SecurityContextHolder.clearContext();
            // 使当前会话失效(如果存在)
            HttpSession session = request.getSession(false);
            if (session != null) {
                session.invalidate();
            }
        }
        return new ResponseEntity<>("signed-out", HttpStatus.OK);
    }  
}

方案2:禁用Spring Security默认登出过滤器

如果应用不需要Spring Security的默认登出处理,可以在安全配置中禁用它,避免与自定义控制器冲突:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .logout(logout -> logout.disable()) // 禁用默认登出过滤器
            // 其他安全配置(如授权、认证规则等)
        return http.build();
    }
}

方案3:调整SecurityContextLogoutHandler的使用方式

如果必须使用SecurityContextLogoutHandler,可以避免让它处理响应,或者调用后重置响应状态:

@RestController
@RequestMapping("/auth/api/access/login/")
public class SignoutController {         
    @GetMapping("signout")
    public ResponseEntity<String> viewlogout(HttpServletRequest request, HttpServletResponse response) {    
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 
        if (authentication != null) {
            // 调用logout时不传response,避免修改响应状态
            new SecurityContextLogoutHandler().logout(request, null, authentication);
            // 若必须传response,可手动重置状态码
            // response.setStatus(HttpStatus.OK.value());
        }
        return new ResponseEntity<>("signed-out", HttpStatus.OK);
    }  
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 20:10:29