authenticationentrypoint不捕获异常,而是主动触发401响应;自定义认证异常(如customauthexception)需继承authenticationexception,在filter或provider中抛出,并通过@controlleradvice统一处理返回结构化json。

在 Spring Security 中,AuthenticationEntryPoint 负责处理未认证请求(如访问需要登录的接口但未携带有效凭证),默认会返回 401 响应。若想将自定义认证异常(比如 CustomAuthException)统一包装并响应给前端,不能直接靠 AuthenticationEntryPoint 捕获异常——因为它本身不参与异常抛出流程,而是“主动触发”的入口逻辑。
理解关键分工:EntryPoint ≠ 异常处理器
AuthenticationEntryPoint 的作用是:当 SecurityContext 中无认证信息、且过滤器链中后续认证失败(或未尝试认证)时,由它发起未认证响应。它不接收或处理异常,所以不能在这里“捕获”自定义异常。
真正抛出自定义认证异常的地方通常是:
- 自定义
AuthenticationProvider或UserDetailsService中(如账号锁定、验证码错误) - JWT 解析失败时的
OncePerRequestFilter(如 token 过期、签名无效) - 方法级安全(
@PreAuthorize)校验失败时的拒绝逻辑
用 AuthenticationException 子类承载业务语义
Spring Security 的异常体系基于 AuthenticationException。要让自定义异常被统一识别和响应,需继承它,并可附加状态码、错误码、提示信息:
public class CustomAuthException extends AuthenticationException {
private final int errorCode;
private final String userMessage;
public CustomAuthException(String msg, int errorCode) {
super(msg);
this.errorCode = errorCode;
this.userMessage = msg;
}
// getter...
}
在过滤器或 Provider 中直接抛出该异常,例如:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
if (!jwtValidator.isValid(token)) {
throw new CustomAuthException("Token 已失效", 1002);
}
通过 AuthenticationExceptionResolver 统一响应
Spring Security 5.7+ 推荐使用 AuthenticationExceptionResolver(配合 ExceptionHandlingConfigurer)替代旧式 AccessDeniedHandler + 全局异常处理器混用的方式。但更通用、可控的做法是结合 AuthenticationEntryPoint 和全局异常处理器:
-
AuthenticationEntryPoint处理「无认证」场景(如未带 token),返回标准 401 - 全局
@ControllerAdvice捕获AuthenticationException及其子类,统一格式化响应
示例:
@ControllerAdvice
public class SecurityExceptionHandler {
@ExceptionHandler(CustomAuthException.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
@ResponseBody
public Result> handleCustomAuthException(CustomAuthException e) {
return Result.fail(e.getErrorCode(), e.getUserMessage());
}
@ExceptionHandler(AuthenticationException.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
@ResponseBody
public Result> handleAuthException(AuthenticationException e) {
return Result.fail(1000, "未授权访问");
}
}
确保异常能被正确传播
注意过滤器中抛出异常后是否被吞掉。例如在自定义 JWT 过滤器中:
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
try {
// 解析 token、设置 Authentication 到 SecurityContext
...
} catch (CustomAuthException e) {
// ⚠️ 必须 re-throw,否则不会进入全局异常处理器
throw e;
}
filterChain.doFilter(request, response);
}
}
如果只是 e.printStackTrace() 或静默忽略,异常就丢失了,自然无法包装。
本质上,不是“包装 AuthenticationEntryPoint 中的异常”,而是让自定义异常沿 Spring MVC 异常传播链到达 @ControllerAdvice,再由它生成结构化响应。EntryPoint 只管兜底的未认证入口,异常响应交给更合适的机制处理。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










