扩展WebSecurityConfigurerAdapter配置OAuth2资源服务器时,无Authorization令牌请求未被拦截的问题及常规处理方案咨询
这个问题我之前踩过坑!默认的BearerTokenAuthenticationFilter确实会在检测不到令牌时直接放行请求,这就导致那些需要OAuth2认证的路径被匿名请求轻易绕过了。下面给你几种常用的解决办法,按需选择就行:
解决方案1:强制路径认证+配置认证入口点
这是最常用的标准做法,核心是明确要求目标路径必须经过认证,同时配置一个AuthenticationEntryPoint来处理未携带令牌的场景,返回标准的401响应。修改你的Security配置代码:
http.authorizeRequests() // 先声明该路径必须认证,优先级高于权限校验 .mvcMatchers(path).authenticated() // 再检查具体的权限要求 .mvcMatchers(path).hasAnyAuthority(...) .and() .oauth2ResourceServer() .jwt() .and() // 配置未认证时的响应逻辑 .authenticationEntryPoint((request, response, authException) -> { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.setContentType("application/json"); response.getWriter().write("{\"error\":\"Missing or invalid Authorization header\"}"); });
这里的.authenticated()是关键——它会告诉Spring Security:访问这个路径的请求必须是已认证的。当请求不带令牌时,Security会触发我们配置的AuthenticationEntryPoint,直接返回401,而不是让请求继续走下去。
解决方案2:自定义过滤器拦截无令牌请求
如果你想直接修改过滤器的行为,不让无令牌请求通过过滤器,可以自定义一个BearerTokenAuthenticationFilter的子类,重写逻辑:
public class CustomBearerAuthFilter extends BearerTokenAuthenticationFilter { public CustomBearerAuthFilter(AuthenticationManager authenticationManager) { super(authenticationManager); } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String token = this.extractToken(request); if (token == null) { // 抛出无凭据异常,直接触发认证失败流程 throw new AuthenticationCredentialsNotFoundException("Authorization header is required"); } // 有令牌的话走原逻辑 super.doFilterInternal(request, response, filterChain); } }
然后在你的Security配置里替换默认的过滤器:
// 替换默认的BearerTokenAuthenticationFilter http.addFilterBefore( new CustomBearerAuthFilter(authenticationManager()), BearerTokenAuthenticationFilter.class ) .authorizeRequests() .mvcMatchers(path).hasAnyAuthority(...) .and() .oauth2ResourceServer().jwt();
这种方式更直接,从过滤器层面就拦截了无令牌请求,不会让请求进入后续的权限校验环节。
解决方案3:使用requiresAuthenticationMatcher(Spring Security 5.4+)
如果你的项目用的是Spring Security 5.4及以上版本,可以用requiresAuthenticationMatcher来指定哪些路径必须触发OAuth2认证,这样过滤器会主动拦截这些路径的无令牌请求:
http.oauth2ResourceServer() .jwt() .and() // 指定需要OAuth2认证的路径 .requiresAuthenticationMatcher(new AntPathRequestMatcher(path)) .and() .authorizeRequests() .mvcMatchers(path).hasAnyAuthority(...);
这个配置会让BearerTokenAuthenticationFilter只对指定路径生效,并且在检测不到令牌时直接触发认证失败,而不是放行请求。
最后补充个小知识点:默认情况下Spring Security会启用匿名认证,所以如果你的路径规则没加.authenticated(),匿名用户会被允许访问。这也是为什么不带令牌的请求能绕过权限校验的原因之一,所以一定要记得给需要认证的路径加上.authenticated()哦。
内容的提问来源于stack exchange,提问作者Albin

