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

自定义Spring Security表达式授权失败时将HTTP 403改为401

解决@PreAuthorize授权失败返回401而非403的问题

你遇到的问题核心在于Spring Security对「认证失败」和「授权失败」的处理逻辑是完全分开的:

  • AuthenticationEntryPoint 只负责处理未认证场景(比如没有JWT令牌、令牌无效等),会触发401;
  • 而你的自定义ExpressionRoot返回false属于已认证但权限不足的授权失败场景,默认会触发AccessDeniedHandler返回403,这就是你配置的HttpStatusEntryPoint没生效的原因。

针对你的Spring Boot 2.1.x版本,只需要在JwtConfigurer中同时配置accessDeniedHandler,让它在授权失败时返回401即可,修改后的代码如下:

import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Collections;

public class JwtConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> { 
    @Override 
    public void configure(HttpSecurity http) throws Exception { 
        http.addFilterBefore(new OwnTokenFilter(), UsernamePasswordAuthenticationFilter.class) 
            .exceptionHandling()
            // 处理未认证场景(比如无token、token无效)返回401
            .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
            // 处理已认证但权限不足的场景返回401
            .accessDeniedHandler((request, response, ex) -> {
                response.setStatus(HttpStatus.UNAUTHORIZED.value());
                response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                // 如果需要返回自定义响应体,可以添加以下内容
                ObjectMapper mapper = new ObjectMapper();
                mapper.writeValue(response.getOutputStream(), 
                    Collections.singletonMap("message", "权限不足,拒绝访问"));
            }); 
    } 
}

额外说明

  1. 如果不需要自定义响应体,也可以简化accessDeniedHandler的实现,直接设置状态码:
.accessDeniedHandler((request, response, ex) -> response.sendError(HttpStatus.UNAUTHORIZED.value()))
  1. 确保你的OwnTokenFilter已经正确将认证信息存入SecurityContext,这样Spring Security才能准确区分「未认证」和「已认证但权限不足」的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:09:19