Spring Boot OAuth2:无需认证端点仍校验Authorization头致401
问题原因分析
你遇到的核心问题是:启用oauth2ResourceServer().jwt()后,Spring Security会自动注册BearerTokenAuthenticationFilter,这个过滤器不区分请求路径,只要请求携带Authorization: Bearer xxx头,就会优先尝试解析JWT令牌。一旦令牌无效,过滤器会直接抛出认证异常并返回401响应,完全绕开了permitAll的授权规则,导致请求根本到不了你的登录控制器。
即使设置anyRequest().permitAll()也无效,因为认证过滤器的执行优先级高于授权决策过滤器(如FilterSecurityInterceptor),无效令牌的请求会被提前拦截。
解决方案
提供两种可行的修复方案,按需选择:
方案一:限制OAuth2资源服务器的生效路径
通过securityMatcher或requestMatchers,让JWT校验逻辑仅对需要认证的路径生效,跳过/api/auth/*路径:
修改SecurityFilterChain配置:
@Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests((authorize) -> authorize .antMatchers("/api/auth/*").permitAll() .anyRequest().authenticated() ) .csrf().disable() .cors().disable() .httpBasic().disable() // 仅对非/auth的API路径启用JWT资源服务器逻辑 .oauth2ResourceServer((oauth2) -> oauth2.jwt((jwt) -> jwt.jwtAuthenticationConverter(jwtToUserConverter)) .requestMatchers(request -> !request.getRequestURI().startsWith("/api/auth/")) ) .sessionManagement((session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .exceptionHandling((exceptions) -> exceptions .authenticationEntryPoint(new BearerTokenAuthenticationEntryPoint()) .accessDeniedHandler(new BearerTokenAccessDeniedHandler()) ); return http.build(); }
方案二:自定义过滤器跳过指定路径
继承BearerTokenAuthenticationFilter,重写shouldNotFilter方法,让过滤器主动跳过/api/auth/*路径的处理:
1. 自定义过滤器类
public class SkipAuthPathBearerFilter extends BearerTokenAuthenticationFilter { public SkipAuthPathBearerFilter(AuthenticationManager authenticationManager) { super(authenticationManager); } @Override protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException { // 跳过所有/api/auth开头的请求 return request.getRequestURI().startsWith("/api/auth/"); } }
2. 替换默认过滤器
在SecurityFilterChain中注册自定义过滤器,替换默认的BearerTokenAuthenticationFilter:
@Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests((authorize) -> authorize .antMatchers("/api/auth/*").permitAll() .anyRequest().authenticated() ) .csrf().disable() .cors().disable() .httpBasic().disable() .oauth2ResourceServer((oauth2) -> oauth2.jwt((jwt) -> jwt.jwtAuthenticationConverter(jwtToUserConverter)) ) .sessionManagement((session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .exceptionHandling((exceptions) -> exceptions .authenticationEntryPoint(new BearerTokenAuthenticationEntryPoint()) .accessDeniedHandler(new BearerTokenAccessDeniedHandler()) ) // 添加自定义过滤器,替换默认的BearerTokenAuthenticationFilter .addFilterBefore(new SkipAuthPathBearerFilter(http.getSharedObject(AuthenticationManager.class)), BearerTokenAuthenticationFilter.class); return http.build(); }
内容的提问来源于stack exchange,提问作者ProRiderZ115
相关产品推荐
相关产品推荐

