spring boot 中应使用 accessdeniedhandler 统一处理未授权异常,需自定义实现并注册到 securityfilterchain;同时收敛 actuator 端点暴露范围,避免仅依赖@controlleradvice或混淆未认证与未授权。

Spring Boot 中处理未授权异常,核心是区分“未认证”(未登录)和“已认证但权限不足”(未授权)两类场景,并在对应环节拦截、响应。不能只靠全局异常处理器,因为很多权限校验发生在过滤器链中,早于 Controller 层。
明确未授权发生的典型位置
未授权(AccessDeniedException)通常出现在以下环节:
- Spring Security 的 Filter 链中,比如访问受
@PreAuthorize或@Secured保护的接口时权限不满足; - 配置了
http.authorizeHttpRequests()后,某请求匹配到.denyAll()或未被任何规则放行; - Actuator 端点启用了 Security 保护,但当前用户角色无权访问
/actuator/env等路径。
用 AccessDeniedHandler 统一响应未授权
这是最标准、最可控的方式。需自定义实现 AccessDeniedHandler 并注册到 Security 配置中:
- 编写处理器类,输出 JSON 格式错误(如
{"code":"A0301","msg":"访问未授权"}); - 在
SecurityFilterChain配置中显式调用.accessDeniedHandler(...); - 确保该配置在
http.authorizeHttpRequests()之后生效,且未被其他安全配置覆盖。
注意:如果项目同时集成了 pac4j 或自定义 Filter,需确认未授权异常是否被提前捕获或跳过 Security 流程——这类异常往往不会触发 AccessDeniedHandler,需单独适配其回调机制。
配合细粒度端点控制,减少未授权触发面
很多“未授权”问题其实源于不该暴露的路径被公开访问,例如 /actuator/env。与其等用户触发 403,不如从源头收敛:
- 在
application-prod.yml中禁用高危端点:management.endpoints.web.exposure.include=health,info; - 关闭默认全量暴露:
management.endpoints.web.exposure.include不设为*; - 对必须暴露的端点加白名单 IP 或反向代理限制(如 Nginx 的
allow/deny)。
避免常见误区
以下做法无法真正解决未授权异常处理:
- 仅靠
@ControllerAdvice捕获AccessDeniedException——它在 Filter 层抛出,进不了 ControllerAdvice 范围; - 把未授权和未认证混为一谈,用同一个
AuthenticationEntryPoint处理; - 依赖路径重命名(如把
/actuator改成/manage)——属于安全错觉,不构成有效防护。











