You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 22:06:05