Spring Boot 中需区分认证异常(用 AuthenticationEntryPoint 返回 JSON)和授权异常(用 AccessDeniedHandler 返回 JSON),并放行 /error 端点;JWT 过滤器内异常须手动处理。

Spring Boot 中处理 Spring Security 异常,关键在于区分两类场景:一类是认证失败(如登录错误),另一类是授权失败(如无权限访问接口),它们由不同机制捕获和响应,不能靠普通的 @ControllerAdvice 统一拦截。
认证异常(AuthenticationException)要自定义 AuthenticationEntryPoint
这类异常发生在用户未登录或登录凭证无效时,比如 BadCredentialsException、UsernameNotFoundException。Spring Security 通过 ExceptionTranslationFilter 捕获后,会交由 AuthenticationEntryPoint 处理。
- 默认行为是重定向到
/login?error(页面跳转),不适用于前后端分离项目 - 需实现
AuthenticationEntryPoint接口,返回 JSON 响应,例如:
class JwtAuthenticationEntryPoint : AuthenticationEntryPoint {<br> override fun commence(request: HttpServletRequest, response: HttpServletResponse, authException: AuthenticationException) {<br> response.status = HttpStatus.UNAUTHORIZED.value()<br> response.contentType = "application/json;charset=UTF-8"<br> response.writer.write(JSONObject(mapOf("code" to 401, "msg" to "未认证或登录已失效")).toString())<br> }<br>}
将后端 Java 接口文档转换为前端 TypeScript 类型定义(interface / type)。输入:飞书文档、Spring Boot 接口文档、Swagger/OpenAPI、手写 API 文档等。输出:包含请求参数与响应结果的 .md 文件,含完整 JSDoc 注释。触发关键词:Java 转 TS、接口转换、生成前端类型、接口文档转 TypeScript、DTO/VO/BO 转 interface、后端文档转前端类型、生成接口类型、类型定义生成。
- 在
SecurityFilterChain中注册:.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
授权异常(AccessDeniedException)要配置 AccessDeniedHandler
这类异常发生在已登录但权限不足时,比如访问了 @PreAuthorize("hasRole('ADMIN')") 保护的接口却只有 USER 角色。
- 默认返回 403 页面或空白响应,前端无法解析
- 实现
AccessDeniedHandler,统一输出结构化 JSON - 同样在
SecurityFilterChain中配置:.accessDeniedHandler(jwtAccessDeniedHandler) - 注意:该处理器只对受保护资源生效,未登录用户触发的是认证异常路径
业务异常与 /error 端点必须显式放行
控制器中抛出的自定义异常(如 @ResponseStatus(HttpStatus.NOT_FOUND))本应返回 404,但若被 Spring Security 拦截 /error 路径,就会因匿名上下文丢失而变成 403。
- 根本原因是
/error默认受保护,BasicErrorController 被拒绝访问 - 必须在安全配置中放行:
.requestMatchers("/error").permitAll() - 同时建议搭配全局
@RestControllerAdvice处理业务异常,确保返回格式与安全异常一致 - 避免混用:不要在过滤器中 throw 异常再指望 @ExceptionHandler 捕获——过滤器链早于 MVC 层
JWT 场景下异常要前置拦截
使用 JWT 时,认证逻辑通常写在自定义过滤器(如 JWTAuthenticationFilter)中。此时异常发生在 Security Filter 链早期,不会走 AuthenticationEntryPoint 标准流程。
- 应在过滤器的
attemptAuthentication或doFilter中 try-catch,手动调用commence()或直接写响应 - 例如捕获
ExpiredJwtException后,设置状态码 401 并写入 JSON 提示“Token 已过期” - 确保异常不向上抛,否则可能被后续 filter 误判为未认证请求

















