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

Spring Boot Security全局异常处理器捕获权限拒绝异常问题

解决Spring Boot全局异常处理器无法捕获AuthorizationDeniedException的问题

问题场景

普通用户访问管理员页面时,期望通过@ControllerAdvice全局异常处理器捕获权限拒绝异常,但终端抛出org.springframework.security.authorization.AuthorizationDeniedException: Access Denied,且该异常未被全局处理器捕获,未使用JWT。

现有实现

  1. 全局异常处理器中针对AccessDeniedException的处理:
@ExceptionHandler(AccessDeniedException.class)
@ResponseStatus(HttpStatus.FORBIDDEN)
public String handleAccessDenied(AccessDeniedException e, Model model) {
    model.addAttribute("errorMessage", e.getMessage());
    return "error";
}
  1. 自定义AccessDeniedHandler:
@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        throw accessDeniedException;
    }
}
  1. SecurityConfig中配置异常处理:
.exceptionHandling(eh -> eh.accessDeniedHandler(customAccessDeniedHandler))

核心问题与解决方案

1. 异常类型不匹配

你当前捕获的AccessDeniedException是Servlet规范定义的异常,而终端抛出的AuthorizationDeniedException是Spring Security 5.6+新增的授权决策异常,二者无继承关系,因此全局处理器未触发。

解决:添加AuthorizationDeniedException的处理方法
在GlobalExceptionHandler中新增对应处理逻辑,覆盖两种权限异常场景:

@ExceptionHandler(AuthorizationDeniedException.class)
@ResponseStatus(HttpStatus.FORBIDDEN)
public String handleAuthorizationDenied(AuthorizationDeniedException e, Model model) {
    model.addAttribute("errorMessage", "权限不足,无法访问该页面");
    return "error";
}

2. 过滤器链异常未传递到DispatcherServlet

Spring Security的过滤器执行在DispatcherServlet之前,直接抛出的异常无法被@ControllerAdvice捕获,需要将异常转发到DispatcherServlet处理。

解决:调整CustomAccessDeniedHandler逻辑
修改自定义处理器,将异常转发到错误请求路径,让DispatcherServlet接管:

@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        // 将异常存入request属性,转发到error路径
        request.setAttribute("javax.servlet.error.exception", accessDeniedException);
        request.getRequestDispatcher("/error").forward(request, response);
    }
}

同时,针对AuthorizationDeniedException,需要在SecurityConfig中补充授权异常的处理(因为该异常不由AccessDeniedHandler处理),可以通过调整异常处理配置:

.exceptionHandling(eh -> eh
    .accessDeniedHandler(customAccessDeniedHandler)
    .authenticationEntryPoint((request, response, ex) -> {
        // 处理未认证场景,同样转发到error页面
        request.setAttribute("javax.servlet.error.exception", ex);
        request.getRequestDispatcher("/error").forward(request, response);
    })
)

3. 简化配置(可选)

如果无需自定义AccessDeniedHandler,可以直接移除相关配置,依赖Spring Security默认的异常处理机制,同时确保全局处理器包含两种异常的处理方法即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 11:15:01