spring security 中权限不足时抛出 accessdeniedexception,需实现并注册 accessdeniedhandler 来自定义处理逻辑,如返回 json 响应或重定向页面,并在 securityconfig 中通过 exceptionhandling().accessdeniedhandler() 注册该 bean。

在 Spring Security 中,当用户拥有认证但缺乏访问资源所需的权限时,会抛出 AccessDeniedException,此时默认行为是跳转到 403 页面或返回错误响应。要自定义处理逻辑,核心是实现并注册一个 AccessDeniedHandler。
实现自定义 AccessDeniedHandler
创建一个类实现 AccessDeniedHandler 接口,重写 handle() 方法,控制拒绝访问时的行为:
- 可返回 JSON 错误响应(适合前后端分离项目)
- 可重定向到统一的权限拒绝页面(适合传统 MVC)
- 可记录日志、触发监控告警等扩展操作
示例(返回 JSON):
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.setContentType("application/json;charset=UTF-8");
String json = "{\"code\":403,\"msg\":\"无访问权限\"}";
response.getWriter().write(json);
}
}
在 SecurityConfig 中注册 Handler
在配置类中通过 http.exceptionHandling().accessDeniedHandler(...) 注册实例:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 推荐使用
@Bean方式声明,便于复用和测试 - 确保该 Bean 在 Security 配置生效前已加载(通常放在
@Configuration类中) - 若同时配置了
authenticationEntryPoint,注意二者分工:前者管“未登录”,后者管“登录但无权”
示例:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public AccessDeniedHandler accessDeniedHandler() {
return new CustomAccessDeniedHandler();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz -> authz
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.exceptionHandling(exception -> exception
.accessDeniedHandler(accessDeniedHandler()) // ← 关键注册点
);
return http.build();
}
}
配合 @PreAuthorize / @PostAuthorize 使用
方法级权限注解(如 @PreAuthorize("hasRole('ADMIN')"))触发的拒绝也会走同一 handler:
- 无需额外配置,只要全局
AccessDeniedHandler已注册,方法级鉴权失败同样生效 - 若需区分接口类型(REST vs 页面),可在 handler 内通过
request.getRequestURI()或请求头判断并分支处理 - 注意:方法级注解需配合
@EnableMethodSecurity(Spring Security 6.0+)或@EnableGlobalMethodSecurity(旧版)启用
常见问题与注意事项
避免踩坑的关键细节:
- 不要在
handle()中调用response.sendRedirect()后再写入响应体,会导致 IllegalStateException - 若使用 Spring Boot + Thymeleaf,返回视图时建议用
RequestDispatcher.forward()而非 redirect,以保留原始请求路径 - handler 中不要抛出新异常(除非明确要被更高层捕获),否则可能绕过预期流程
- 测试时可通过模拟带 token 但无权限的请求,验证响应状态码和内容是否符合预期
不复杂但容易忽略。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










