Spring WebFlux Security中permitAll()无法跳过令牌验证过滤器问题
问题根源
你遇到的核心问题是:permitAll()控制的是授权决策环节,而你添加的令牌验证过滤器是在认证阶段执行的,它不会自动识别授权规则里的放行路径。
Spring WebFlux Security的过滤器链执行顺序是:
- 各种前置过滤器(包括你添加的
tokenValidation) - 认证过滤器
- 授权决策(也就是
permitAll()/authenticated()生效的环节)
所以哪怕你给/auth/api/v1/cred/**配置了permitAll(),请求还是会先经过tokenValidation过滤器,再进入授权判断环节——这时候授权环节会放行,但过滤器已经执行过了。
解决方案
有两种常用的解决方式,根据你的场景选择:
方案1:在令牌验证过滤器内主动跳过指定路径
修改tokenValidation的逻辑,先判断请求路径是否属于放行范围,如果是就直接跳过验证:
@Override public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { String requestPath = exchange.getRequest().getPath().value(); // 匹配所有/auth/api/v1/cred开头的路径 if (requestPath.startsWith("/auth/api/v1/cred/")) { return chain.filter(exchange); } // 原来的令牌验证逻辑 // ... }
这种方式适合过滤器逻辑简单、只想跳过少量路径的场景。
方案2:拆分SecurityWebFilterChain,为放行路径单独配置
创建两个优先级不同的SecurityWebFilterChain,让放行路径的配置先执行,且不添加令牌验证过滤器:
第一个配置(处理放行路径,优先级更高)
@Bean @Order(1) // 数字越小优先级越高 public SecurityWebFilterChain publicEndpointSecurity(ServerHttpSecurity http) throws Exception { http .securityMatcher("/auth/api/v1/cred/**") // 只对该路径生效 .csrf(ServerHttpSecurity.CsrfSpec::disable) .authorizeExchange(exchanges -> exchanges.anyExchange().permitAll()) .httpBasic(ServerHttpSecurity.HttpBasicSpec::disable) .formLogin(ServerHttpSecurity.FormLoginSpec::disable); return http.build(); }
第二个配置(处理其他所有需要认证的路径)
@Bean @Order(2) public SecurityWebFilterChain securedEndpointSecurity(ServerHttpSecurity http) throws Exception { http .csrf(ServerHttpSecurity.CsrfSpec::disable) .authorizeExchange(exchanges -> exchanges.anyExchange().authenticated()) .addFilterBefore(tokenValidation, SecurityWebFiltersOrder.AUTHENTICATION) .addFilterAfter(addXTrustedSourceHeaderFilter, SecurityWebFiltersOrder.AUTHENTICATION) .httpBasic(ServerHttpSecurity.HttpBasicSpec::disable) .formLogin(ServerHttpSecurity.FormLoginSpec::disable); return http.build(); }
这种方式更清晰,适合有大量不同权限规则的场景,每个配置只负责自己的路径范围。
额外验证点
- 确认应用是否有上下文路径:如果你的应用部署时带有上下文路径(比如
/api),那么pathMatchers里需要写成/api/auth/api/v1/cred/**,或者结合server.servlet.context-path配置调整匹配规则。 - 检查路径匹配规则:
/**会匹配该路径下的所有子路径,/auth/api/v1/cred/login/确实会被/auth/api/v1/cred/**匹配到,这点你已经确认过,没问题。
内容的提问来源于stack exchange,提问作者Siva V
相关产品推荐
相关产品推荐

