WebFlux中如何从ReactiveSecurityContextHolder获取当前登录用户
Spring Boot 响应式场景ReactiveSecurityContextHolder集成解决方案
问题根因
ReactiveSecurityContextHolder返回空、回调方法未触发的核心原因通常是以下两类:
- 安全配置错误,未开启响应式安全上下文的传播能力
- 当前请求未经过认证流程,安全上下文未被初始化,因此返回空Mono
完整集成步骤
1. 确认依赖与基础注解
首先确保项目使用的是WebFlux响应式栈,而非Servlet栈的Spring MVC,引入必要依赖:
<!-- 以Maven为例 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
安全配置类必须使用@EnableWebFluxSecurity注解,禁止使用Servlet栈的@EnableWebSecurity。
2. 编写基础安全配置
示例配置如下,可根据自身业务调整认证规则:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; import org.springframework.security.config.web.server.ServerHttpSecurity; import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.web.server.SecurityWebFilterChain; import org.springframework.security.web.server.context.WebSessionServerSecurityContextRepository; @Configuration @EnableWebFluxSecurity public class ReactiveSecurityConfig { @Bean public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { return http .authorizeExchange(exchange -> exchange // 配置需要认证的路径,示例所有接口都需要认证 .anyExchange().authenticated() ) // 显式指定安全上下文存储实现,默认基于Session存储,无状态认证场景可替换为自定义实现 .securityContextRepository(WebSessionServerSecurityContextRepository.DEFAULT) // 开启表单登录用于测试,生产环境可替换为JWT、OAuth2等认证方式 .formLogin(Customizer.withDefaults()) .build(); } // 测试用内存用户,生产环境替换为自定义用户查询逻辑 @Bean public MapReactiveUserDetailsService userDetailsService() { UserDetails testUser = User.withDefaultPasswordEncoder() .username("test") .password("123456") .roles("USER") .build(); return new MapReactiveUserDetailsService(testUser); } }
3. 编写测试接口
原有代码逻辑本身没有问题,补充空场景的处理即可:
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.ReactiveSecurityContextHolder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Mono; @RestController public class AuthTestController { private static final Logger log = LoggerFactory.getLogger(AuthTestController.class); @GetMapping("/get-auth") public Mono<Authentication> getCurrentAuth() { return ReactiveSecurityContextHolder.getContext() .map(securityContext -> securityContext.getAuthentication()) .doOnNext(auth -> log.info("获取到认证信息:{}", auth)) .doOnSuccess(auth -> { if (auth == null) { log.warn("当前请求未认证,安全上下文为空"); } else { log.info("认证信息获取成功:{}", auth); } }) // 可选:未登录场景抛出异常或返回默认值,避免返回null .switchIfEmpty(Mono.error(new RuntimeException("当前用户未登录"))); } }
验证方式
启动项目后先访问任意接口,会跳转至登录页,输入用户名test、密码123456完成认证后,再调用/get-auth接口即可正常拿到认证信息,doOnNext、doOnSuccess都会正常触发。
内容的提问来源于stack exchange,提问作者TariqN
相关产品推荐
相关产品推荐

