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

为何Spring Security在此场景下会重定向至/error?

问题原因分析

你看到的Securing GET /error是因为**response.sendError(HttpServletResponse.SC_FORBIDDEN)触发了Servlet容器的错误页面转发机制**。

当调用sendError()时,Servlet容器会判定需要展示错误页面,自动将请求转发到Spring Boot默认配置的/error端点(由ErrorMvcAutoConfiguration自动注册)。而你的SecurityFilterChain配置了anyRequest().authenticated(),所以/error请求也会经过Spring Security过滤器链,导致日志中出现第二次过滤器调用记录。

另外,虽然你在sendError()之后写了JSON响应,但容器的错误转发会覆盖你输出的内容,最终客户端收到的是Spring Boot默认的错误响应,而非你自定义的JSON。

解决方案

修改ApplicationAuthenticationEntryPoint的commence方法,不要使用response.sendError(),直接设置响应状态码、内容类型并写入JSON内容:

public class ApplicationAuthenticationEntryPoint implements AuthenticationEntryPoint {

    private final ObjectMapper mapper = new ObjectMapper();

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        // 直接设置状态码,不触发容器错误转发
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding("UTF-8");
        
        ObjectNode errorNode = mapper.createObjectNode()
                .put("timestamp", LocalDateTime.now().toEpochSecond(ZoneOffset.of("-3")))
                .put("message", "Access denied to resource");
        
        response.getWriter().write(mapper.writeValueAsString(errorNode));
    }
}
额外说明
  • 移除sendError()后,Servlet容器不会再转发到/error,过滤器链只会执行一次,你的自定义JSON响应会直接返回给客户端。
  • 如果需要统一处理其他错误场景(比如控制器抛出的异常),可以单独配置@ControllerAdvice来处理,避免和Spring Security的认证异常处理冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 20:34:54