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

Spring Security 6中使用SimpleUrlAuthenticationFailureHandler保留HTTP状态码

问题分析与解决方案

你的问题根源在于SimpleUrlAuthenticationFailureHandler的默认跳转逻辑会覆盖你设置的状态码:当调用super.onAuthenticationFailure()时,默认会触发重定向到LOGIN_FAILURE_URL,重定向本身会返回3xx状态码,浏览器再请求目标URL时,目标端点默认返回200,最终导致你设置的401被覆盖。

以下是两种可行的解决方式:


方案1:不跳转,直接返回401与错误信息

如果不需要跳转到指定页面,仅需给客户端返回401状态码和认证失败信息,可以跳过父类的跳转逻辑,直接自定义响应:

public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {

    @Override
    public void onAuthenticationFailure(
            HttpServletRequest request,
            HttpServletResponse response,
            AuthenticationException exception) throws IOException, ServletException {
        // 设置401未授权状态码
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        // 可选:返回JSON格式的错误信息(适配XHR请求)
        response.setContentType("application/json;charset=UTF-8");
        String errorMsg = String.format("{\"code\":401,\"message\":\"认证失败:%s\"}", exception.getMessage());
        response.getWriter().write(errorMsg);
        
        // 不要调用super.onAuthenticationFailure(),避免触发跳转覆盖状态码
    }
}

方案2:跳转到指定端点并保留401状态码

如果必须跳转到LOGIN_FAILURE_URL,需要修改跳转方式为**forward(转发)**而非默认的redirect(重定向),同时确保目标端点返回401状态码:

步骤1:自定义FailureHandler

public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {

    private static final String LOGIN_FAILURE_URL = "/login-failure";

    public CustomAuthenticationFailureHandler() {
        super.setDefaultFailureUrl(LOGIN_FAILURE_URL);
        super.setUseForward(true); // 启用forward转发,而非redirect重定向
    }

    @Override
    public void onAuthenticationFailure(
            HttpServletRequest request,
            HttpServletResponse response,
            AuthenticationException exception) throws IOException, ServletException {
        // 预先设置401状态码
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        // 调用父类方法触发forward转发
        super.onAuthenticationFailure(request, response, exception);
    }
}

步骤2:给LOGIN_FAILURE_URL端点设置401返回值

@Controller
public class LoginFailureController {

    @GetMapping("/login-failure")
    public ResponseEntity<String> handleLoginFailure() {
        // 明确返回401状态码和错误内容
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("认证失败,请检查账号密码");
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 10:38:07