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
相关产品推荐
相关产品推荐

