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

Spring Boot HttpSecurity异常处理问题:无法跳转自定义403页面

修复Spring Security accessDeniedPage导致StackOverflowError的问题

问题根源

你遇到的栈溢出是因为自定义403页面的路径/error/403没有被Spring Security放行。当用户触发权限拒绝时,系统尝试跳转到/error/403,但Spring Security会对这个路径再次进行权限校验,由于未放行,又触发权限拒绝,形成无限循环,最终导致StackOverflowError。

修复方案

方案1:放行403页面路径

在authorizeHttpRequests中添加对/error/403的放行配置,让所有用户都能访问该页面:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    return http
            .exceptionHandling(excHand -> excHand.accessDeniedPage("/error/403"))
            .csrf(csrfCustomizer->csrfCustomizer.disable())
            .authorizeHttpRequests(auth -> auth
                    .requestMatchers("/error/403").permitAll() // 新增放行配置
                    .requestMatchers("/").hasAnyRole("USER")
            )
            .formLogin(formLogin -> formLogin
                    .loginPage("/login")
                    .permitAll()
            )
            .logout(logout -> logout.logoutUrl("/logout")
                    .permitAll()
            )
            .build();
}

方案2:使用自定义AccessDeniedHandler替代accessDeniedPage

如果需要更灵活的权限拒绝处理逻辑,可以直接实现AccessDeniedHandler接口,避免路径跳转可能带来的循环问题:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    return http
            .exceptionHandling(excHand -> excHand.accessDeniedHandler((request, response, accessDeniedException) -> {
                // 设置响应状态码为403
                response.setStatus(HttpServletResponse.SC_FORBIDDEN);
                // 转发到自定义403页面(或直接返回JSON)
                request.getRequestDispatcher("/error/403").forward(request, response);
            }))
            .csrf(csrfCustomizer->csrfCustomizer.disable())
            .authorizeHttpRequests(auth -> auth
                    .requestMatchers("/error/403").permitAll() // 同样需要放行该路径
                    .requestMatchers("/").hasAnyRole("USER")
            )
            .formLogin(formLogin -> formLogin
                    .loginPage("/login")
                    .permitAll()
            )
            .logout(logout -> logout.logoutUrl("/logout")
                    .permitAll()
            )
            .build();
}

额外验证点

  • 确保/error/403路径对应的控制器或静态页面确实存在,比如:
    @Controller
    public class ErrorController {
        @GetMapping("/error/403")
        public String accessDenied() {
            return "error/403"; // 对应templates下的error/403.html(如果用Thymeleaf)
        }
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 10:55:23