如何解决使用EnableWebFluxSecurity时出现的401 Unauthorized问题
使用Spring Boot 3.1.1,配置了包含@EnableWebFluxSecurity等注解的HttpSecurityConfig,调用接口POST /user/block-users时返回401 Unauthorized错误。
相关代码
Security配置类
@Configuration @EnableWebFluxSecurity @EnableHotmartSecurity @EnableReactiveMethodSecurity(useAuthorizationManager = true) class HttpSecurityConfig { @Bean fun springSecurityFilterChain(http: ServerHttpSecurity ): SecurityWebFilterChain { return http .httpBasic{} .cors {} .formLogin { configurer -> configurer.disable() } .logout { configurer -> configurer.disable() } .csrf { configurer -> configurer.disable() } .authorizeExchange { it.pathMatchers(HttpMethod.OPTIONS).permitAll() it.pathMatchers("/management/health").permitAll() it.pathMatchers("/management/**").hasRole("ACTUATOR") }.build() } }
Maven父依赖
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.1.1</version> <relativePath/> <!-- lookup parent from repository --> </parent>
错误日志
PathMatcherServerWebExchangeMatcher{pattern='/management/**', method=null} 2023-07-21T23:40:28.995-03:00 DEBUG [api-teste,,] 52726 --- [ parallel-1] athPatternParserServerWebExchangeMatcher : Request 'POST /user/block-users' doesn't match 'null /management/**' 2023-07-21T23:40:28.996-03:00 DEBUG [api-teste,,] 52726 --- [ parallel-1] o.s.s.w.s.u.m.OrServerWebExchangeMatcher : No matches found 2023-07-21T23:40:29.001-03:00 DEBUG [api-teste,,] 52726 --- [ parallel-1] o.s.s.w.s.a.AuthorizationWebFilter : Authorization failed: Access Denied 2023-07-21T23:40:29.028-03:00 DEBUG [api-teste,,] 52726 --- [ parallel-1] ebSessionServerSecurityContextRepository : No SecurityContext found in WebSession: 'org.springframework.web.server.session.InMemoryWebSessionStore$InMemoryWebSession@35f2c0da' 2023-07-21T23:40:29.029-03:00 DEBUG [api-teste,,] 52726 --- [ parallel-1] DelegatingServerAuthenticationEntryPoint : Trying to match using org.springframework.security.config.web.server.ServerHttpSecurity$HttpBasicSpec$$Lambda$1297/0x0000000801395e08@13e6577c 2023-07-21T23:40:29.030-03:00 DEBUG [api-teste,,] 52726 --- [ parallel-1] DelegatingServerAuthenticationEntryPoint : No match found. Using default entry point org.springframework.security.web.server.authentication.HttpBasicServerAuthenticationEntryPoint@5b8b2deb 2023-07-21T23:40:29.032-03:00 DEBUG [api-teste,,] 52726 --- [ parallel-1] o.s.w.s.adapter.HttpWebHandlerAdapter : [4984311b-1] Completed 401 UNAUTHORIZED 2023-07-21T23:40:29.060-03:00 DEBUG [api-teste,,] 52726 --- [ parallel-1] r.n.http.server.HttpServerOperations : [4984311b-1, L:/[0:0:0:0:0:0:0:1]:8080 - R:/[0:0:0:0:0:0:0:1]:62743] Last HTTP response frame 2023-07-21T23:40:29.060-03:00 DEBUG [api-teste,,] 52726 --- [ parallel-1] r.n.http.server.HttpServerOperations : [4984311b-1, L:/[0:0:0:0:0:0:0:1]:8080 - R:/[0:0:0:0:0:0:0:1]:62743] No sendHeaders() called before complete, sending zero-length header 2023-07-21T23:40:29.076-03:00 DEBUG [api-teste,,] 52726 --- [ctor-http-nio-3] r.n.http.server.HttpServerOperations : [4984311b-1, L:/[0:0:0:0:0:0:0:1]:8080 - R:/[0:0:0:0:0:0:0:1]:62743] Decreasing pending responses, now 0 2023-07-21T23:40:29.078-03:00 DEBUG [api-teste,,] 52726 --- [ctor-http-nio-3] r.netty.channel.ChannelOperations : [4984311b-1, L:/[0:0:0:0:0:0:0:1]:8080 - R:/[0:0:0:0:0:0:0:1]:62743] [HttpServer] Channel inbound receiver cancelled (subscription disposed). 2023-07-21T23:40:29.082-03:00 DEBUG [api-teste,,] 52726 --- [ctor-http-nio-3] reactor.netty.channel.FluxReceive : [4984311b-1, L:/[0:0:0:0:0:0:0:1]:8080 - R:/[0:0:0:0:0:0:0:1]:62743] [terminated=true, cancelled=true, pending=0, error=null]: dropping frame LAST_CONTENT(decodeResult: success, content: PooledSlicedByteBuf(ridx: 0, widx: 15, cap: 15/15, unwrapped: PooledUnsafeDirectByteBuf(ridx: 1647, widx: 1647, cap: 2048))) 2023-07-21T23:40:29.083-03:00 DEBUG [api-teste,,] 52726 --- [ctor-http-nio-3] r.n.http.server.HttpServerOperations : [4984311b-1, L:/[0:0:0:0:0:0:0:1]:8080 - R:/[0:0:0:0:0:0:0:1]:62743] Last HTTP packet was sent, terminating the channel
问题原因
从日志可见,请求POST /user/block-users未匹配到任何已配置的授权规则,Spring Security默认会拦截所有未明确配置的请求,要求用户完成认证,因此返回401 Unauthorized。当前配置仅放开了OPTIONS请求、/management/health路径,以及要求ACTUATOR角色的/management/**路径,其余请求均未设置授权规则。
解决办法
根据接口的权限需求,选择以下方案之一:
方案1:放开该接口的访问权限(无需认证)
在authorizeExchange中添加对/user/block-users的放行规则:
.authorizeExchange { it.pathMatchers(HttpMethod.OPTIONS).permitAll() it.pathMatchers("/management/health").permitAll() it.pathMatchers("/management/**").hasRole("ACTUATOR") // 添加该行,允许POST /user/block-users无需认证 it.pathMatchers(HttpMethod.POST, "/user/block-users").permitAll() }
方案2:配置该接口需要特定权限
如果接口需要特定角色或权限才能访问,配置对应的规则:
.authorizeExchange { it.pathMatchers(HttpMethod.OPTIONS).permitAll() it.pathMatchers("/management/health").permitAll() it.pathMatchers("/management/**").hasRole("ACTUATOR") // 要求用户拥有ADMIN角色才能访问该接口 it.pathMatchers(HttpMethod.POST, "/user/block-users").hasRole("ADMIN") }
方案3:使用方法级权限控制
由于已经添加了@EnableReactiveMethodSecurity(useAuthorizationManager = true),可以在接口方法上使用@PreAuthorize等注解控制权限,此时需要确保Security配置允许请求进入过滤器,可在authorizeExchange末尾添加:
.authorizeExchange { it.pathMatchers(HttpMethod.OPTIONS).permitAll() it.pathMatchers("/management/health").permitAll() it.pathMatchers("/management/**").hasRole("ACTUATOR") // 允许所有请求先通过过滤器,由方法级注解控制权限 it.anyExchange().permitAll() }
然后在接口方法上添加注解:
@PostMapping("/user/block-users") @PreAuthorize("hasRole('ADMIN')") fun blockUsers(): Mono<ResponseEntity<Void>> { // 接口逻辑 }
内容的提问来源于stack exchange,提问作者fel3180
相关产品推荐
相关产品推荐

