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

Spring Boot Security:未带Bearer Token返回403而非401问题解决

Spring Boot Security权限异常处理问题及解决办法

问题描述

  1. 携带普通用户的Bearer Token访问标注@PreAuthorize("hasAnyAuthority('ADMIN')")的接口,返回401 Unauthorized,期望返回403 Forbidden。
  2. 不携带Bearer Token时,始终返回403 Forbidden而非401 Unauthorized,且全局异常处理器中的handleAccessDeniedError方法未触发。

相关代码

全局异常处理器片段

@ExceptionHandler({AccessDeniedException.class})
protected ResponseEntity<Object> handleAccessDeniedError(final AccessDeniedException exception) {
    log.error(exception.getMessage(), exception);

    Error error = Error.builder()
            .httpStatus(HttpStatus.FORBIDDEN)
            .header(Error.Header.AUTH_ERROR.getName())
            .build();
    return new ResponseEntity<>(error, HttpStatus.FORBIDDEN);
}

接口代码片段

@GetMapping
@PreAuthorize("hasAnyAuthority('ADMIN')")
public Response<?> getUsers(@RequestBody @Valid UserListRequest listRequest) {
    // 接口逻辑
}

问题原因及解决办法

问题1:权限不足返回401而非403

原因:Spring Security默认异常处理机制中,若认证过滤器(如Bearer Token过滤器)在权限校验前执行,当权限校验失败抛出AccessDeniedException时,可能被认证相关的异常处理器拦截,错误转换为401响应;或Security配置未正确区分认证失败(401)与授权失败(403)的异常处理逻辑。

解决办法:
在Security配置类中,通过exceptionHandling()明确配置授权失败的处理器:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            // 其他配置...
            .exceptionHandling()
                // 认证失败(未登录/Token无效)返回401
                .authenticationEntryPoint((request, response, authException) -> {
                    response.setStatus(HttpStatus.UNAUTHORIZED.value());
                    // 可自定义响应体格式
                })
                // 授权失败(权限不足)返回403
                .accessDeniedHandler((request, response, accessDeniedException) -> {
                    response.setStatus(HttpStatus.FORBIDDEN.value());
                    // 可调用全局异常处理器的逻辑输出统一错误格式
                });
    }
}

同时确保@PreAuthorize的权限校验在认证完成后执行,即过滤器链中认证过滤器(如BearerTokenAuthenticationFilter)在权限过滤器(如FilterSecurityInterceptor)之前。

问题2:未携带Token返回403且全局异常处理器未触发

原因:未携带Token时,Spring Security会触发AuthenticationEntryPoint(认证入口点),默认实现可能返回403;此时抛出的是AuthenticationException(如InsufficientAuthenticationException),而非AccessDeniedException,因此全局异常处理器中对应AccessDeniedException的方法不会触发。

解决办法:

  1. 调整Security配置,让未认证请求返回401:
    在Security配置中配置authenticationEntryPoint,明确未认证时返回401:
    http.exceptionHandling()
        .authenticationEntryPoint((request, response, authException) -> {
            // 自定义401响应体
            Error error = Error.builder()
                    .httpStatus(HttpStatus.UNAUTHORIZED)
                    .header(Error.Header.AUTH_ERROR.getName())
                    .build();
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            new ObjectMapper().writeValue(response.getOutputStream(), error);
        });
    
  2. 全局异常处理器添加AuthenticationException处理:
    若希望通过全局异常处理器处理认证失败异常,添加对应的@ExceptionHandler方法:
    @ExceptionHandler({AuthenticationException.class})
    protected ResponseEntity<Object> handleAuthenticationError(final AuthenticationException exception) {
        log.error(exception.getMessage(), exception);
    
        Error error = Error.builder()
                .httpStatus(HttpStatus.UNAUTHORIZED)
                .header(Error.Header.AUTH_ERROR.getName())
                .build();
        return new ResponseEntity<>(error, HttpStatus.UNAUTHORIZED);
    }
    
    注意:若同时配置了Security的authenticationEntryPoint和全局异常处理器,需确保过滤器链未提前拦截异常,可通过调整过滤器顺序或禁用默认异常处理让全局处理器生效。

内容的提问来源于stack exchange,提问作者Sercan Noyan Germiyanoğlu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 23:45:07