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

Spring Boot中403 Forbidden自定义异常处理器的问题

问题描述

我用Spring Boot开发后端应用,采用Keycloak做用户与权限管理,目前在自定义403 Forbidden错误的异常处理器时遇到问题。

未配置全局异常处理器时,能针对未授权令牌返回正确的401和403响应,但我需要全局异常处理器处理意外错误,代码如下:

@ExceptionHandler(value = Exception.class)
public ResponseEntity<String> generalExceptionHandler(Exception e) {
    log.error(e.getMessage());
    return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("General Error");
}

如果不配置其他异常处理器,所有导致401或403响应的场景都会被这个全局处理器接管,不符合我的需求——我希望这两类错误能返回对应的正确消息。

于是我开发了针对AccessDeniedException的异常处理器:

@ExceptionHandler(value = AccessDeniedException.class)
public ResponseEntity<String> accessDeniedExceptionHandler(Exception e) {
    log.error(e.getMessage());
    return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Access is denied");
}

现在所有401场景能被这个处理器正确处理,但403 Forbidden场景也会被它捕获,我需要区分这两类错误,为403单独设置处理器返回对应消息。

解决方案

核心问题是你混淆了401和403对应的异常类型:

  • 401(未授权,比如令牌无效、过期)对应的是认证异常,属于AuthenticationException的子类(Keycloak场景下常见的有InvalidTokenException、TokenExpiredException等)
  • 403(禁止访问,令牌有效但无对应权限)对应的才是AccessDeniedException

你需要分别为这两类异常编写处理器,利用Spring异常处理器的优先级规则(优先匹配最具体的异常类型)来区分:

  1. 编写401对应的认证异常处理器:
@ExceptionHandler(value = AuthenticationException.class)
public ResponseEntity<String> authenticationExceptionHandler(AuthenticationException e) {
    log.error(e.getMessage());
    return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("无效或过期的令牌");
}
  1. 编写403对应的权限异常处理器:
@ExceptionHandler(value = AccessDeniedException.class)
public ResponseEntity<String> accessDeniedExceptionHandler(AccessDeniedException e) {
    log.error(e.getMessage());
    return ResponseEntity.status(HttpStatus.FORBIDDEN).body("你没有访问该资源的权限");
}
  1. 保留全局异常处理器(处理其他所有未捕获的意外错误):
@ExceptionHandler(value = Exception.class)
public ResponseEntity<String> generalExceptionHandler(Exception e) {
    log.error(e.getMessage());
    return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("General Error");
}

关键说明

Spring异常处理器会优先匹配最具体的异常类型,所以AuthenticationException和AccessDeniedException会被各自的处理器捕获,不会走到全局的Exception处理器。如果需要更精准匹配Keycloak的特定认证异常(比如TokenExpiredException),可以单独为该异常编写处理器,优先级会比AuthenticationException更高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 19:01:03