无法使用 ReactiveSecurityContextHolder 检索身份验证信息

问题描述 投票:0回答:1

在我的 Spring Boot 应用程序中,我使用 spring-security 并实现了

WebFilter
以在
Authentication
中设置
ReactiveSecurityContextHolder
。然而,当我尝试检索它时,
Authentication
对象变为空。 这是重现我面临的问题的代码示例片段。

Spring-boot应用程序启动类如下:

@EnableWebFlux
@SpringBootApplication
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
@Configuration
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
    @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
        return http
                .csrf(csrfSpec -> csrfSpec.disable())
                .authorizeExchange(auth -> auth.pathMatchers(HttpMethod.GET, "/**")
                        .authenticated())
                .httpBasic(httpBasicSpec -> httpBasicSpec.disable())
                .addFilterBefore(customWebFilter(), SecurityWebFiltersOrder.AUTHENTICATION)
                .build();
    }
    public WebFilter customWebFilter() {
        return (exchange, chain) -> {
            Authentication authenticatedToken =
                    new PreAuthenticatedAuthenticationToken("User_PreAuthenticated", "");
            authenticatedToken.setAuthenticated(true);
            return chain.filter(exchange)
                    .contextWrite(ReactiveSecurityContextHolder.withAuthentication(authenticatedToken));
        };
    }
}

这是我尝试从

Authentication
检索
ReactiveSecurityContextHolder
的代码,但是身份验证对象将为空。

// This authentication object is coming null.
Authentication authentication = ReactiveSecurityContextHolder.getContext()
.map(SecurityContext::getAuthentication)
.toFuture().getNow(null); 
        

我已经参考了多个 StackOverflow 问题和文档,但是我无法解决这个特定问题。我错过了什么吗?

spring-boot spring-security spring-webflux
1个回答
0
投票

当你处于反应范式时,你应该始终保持反应。 在反应式应用程序中,

Authentication
存储在订阅者上下文中,而不是存储在
ThreadLocal
中,因为它通常在 Spring MVC 中实现(不是反应式应用程序)。

因此,当您尝试以这种方式检索

Authentication
时:

// This authentication object is coming null.
Authentication authentication = ReactiveSecurityContextHolder.getContext()
.map(SecurityContext::getAuthentication)
.toFuture().getNow(null); 

您将获得 null,因为

Authentication
仅限于 subscriber 上下文。

您可能会注意到

ReactiveSecurityContextHolder.getContext()
返回
Mono
,因此您应该在反应式链中调用它,而不用阻塞调用或其他
subscribe()
方法来破坏它

例如:

@GetMapping
public Mono<ResponseEntity<String>> endpoint() {
    return ReactiveSecurityContextHolder.getContext()
            .map(securityContext -> securityContext.getAuthentication())
            .map(authentication -> authentication.getName())
            .map(userName -> ResponseEntity.ok(userName));
}
© www.soinside.com 2019 - 2024. All rights reserved.