自定义Spring Security表达式授权失败时将HTTP 403改为401
你遇到的问题核心在于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", "权限不足,拒绝访问")); }); } }
额外说明
- 如果不需要自定义响应体,也可以简化
accessDeniedHandler的实现,直接设置状态码:
.accessDeniedHandler((request, response, ex) -> response.sendError(HttpStatus.UNAUTHORIZED.value()))
- 确保你的
OwnTokenFilter已经正确将认证信息存入SecurityContext,这样Spring Security才能准确区分「未认证」和「已认证但权限不足」的场景。
内容的提问来源于stack exchange,提问作者Neophyn33
相关产品推荐
相关产品推荐

