Spring WebFlux 中的 ReactiveSecurityContextHolder 为空
ReactiveSecurityContextHolder is empty in Spring WebFlux
我正在尝试将 ReactiveSecurityContextHolder 与 Spring WebFlux 一起使用。不幸的是,SecurityContext 是空的:
@Configuration
public class Router {
@Bean
public RouterFunction<ServerResponse> routes(Handler handler) {
return nest(
path("/bill"),
route(
GET("/").and(accept(APPLICATION_JSON)), handler::all));
}
@Component
class Handler {
Mono<ServerResponse> all(ServerRequest request) {
ReactiveSecurityContextHolder.getContext()
.switchIfEmpty(Mono.error(new IllegalStateException("ReactiveSecurityContext is empty")))
.map(SecurityContext::getAuthentication)
.map(Authentication::getName)
.flatMap(s -> Mono.just("Hi " + s))
.subscribe(
System.out::println,
Throwable::printStackTrace,
() -> System.out.println("completed without a value")
);
return ok().build();
}
}
}
此代码总是抛出 IllegalStateException。
如果我添加如图所示的 subscriberContext here :
Authentication authentication = new TestingAuthenticationToken("admin", "password", "ROLE_ADMIN");
ReactiveSecurityContextHolder.getContext()
.switchIfEmpty(Mono.error(new IllegalStateException("ReactiveSecurityContext is empty")))
.map(SecurityContext::getAuthentication)
.map(Authentication::getName)
.flatMap(s -> Mono.just("Hi " + s))
.subscriberContext(ReactiveSecurityContextHolder.withAuthentication(authentication))
.subscribe(
System.out::println,
Throwable::printStackTrace,
() -> System.out.println("completed without a value")
);
它工作正常并打印 "Hi admin"。但这不是重点,文章说"In a WebFlux application the subscriberContext
is automatically setup using ReactorContextWebFilter
"。所以我应该能够获取登录的用户。
我有这样的配置:
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class SecurityConfig {
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
return http.authorizeExchange()
.anyExchange().authenticated()
.and().formLogin()
.and().build();
}
@Bean
public MapReactiveUserDetailsService userDetailsService() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
UserDetails admin = User.withDefaultPasswordEncoder()
.username("admin")
.password("password")
.roles("ADMIN")
.build();
return new MapReactiveUserDetailsService(user, admin);
}
}
我是不是漏掉了什么?如果我在 ReactorContextWebFilter 中放置断点,我可以看到它在每个请求之前被正确调用。但是我的 ReactiveSecurityContextHolder 总是空的...
您必须 return 您要访问的流 ReactiveSecurityContextHolder。您不能在另一个流中订阅 或 您必须手动执行 Reactor 上下文切换。
@Component
class Handler {
Mono<ServerResponse> all(ServerRequest request) {
return ReactiveSecurityContextHolder.getContext()
.switchIfEmpty(Mono.error(new IllegalStateException("ReactiveSecurityContext is empty")))
.map(SecurityContext::getAuthentication)
.map(Authentication::getName)
.flatMap(s -> Mono.just("Hi " + s))
.doOnNext(System.out::println)
.doOnError(Throwable::printStackTrace)
.doOnSuccess(s -> System.out.println("completed without value: " + s))
.flatMap(s -> ServerResponse.ok().build());
}
}
我正在尝试将 ReactiveSecurityContextHolder 与 Spring WebFlux 一起使用。不幸的是,SecurityContext 是空的:
@Configuration
public class Router {
@Bean
public RouterFunction<ServerResponse> routes(Handler handler) {
return nest(
path("/bill"),
route(
GET("/").and(accept(APPLICATION_JSON)), handler::all));
}
@Component
class Handler {
Mono<ServerResponse> all(ServerRequest request) {
ReactiveSecurityContextHolder.getContext()
.switchIfEmpty(Mono.error(new IllegalStateException("ReactiveSecurityContext is empty")))
.map(SecurityContext::getAuthentication)
.map(Authentication::getName)
.flatMap(s -> Mono.just("Hi " + s))
.subscribe(
System.out::println,
Throwable::printStackTrace,
() -> System.out.println("completed without a value")
);
return ok().build();
}
}
}
此代码总是抛出 IllegalStateException。
如果我添加如图所示的 subscriberContext here :
Authentication authentication = new TestingAuthenticationToken("admin", "password", "ROLE_ADMIN");
ReactiveSecurityContextHolder.getContext()
.switchIfEmpty(Mono.error(new IllegalStateException("ReactiveSecurityContext is empty")))
.map(SecurityContext::getAuthentication)
.map(Authentication::getName)
.flatMap(s -> Mono.just("Hi " + s))
.subscriberContext(ReactiveSecurityContextHolder.withAuthentication(authentication))
.subscribe(
System.out::println,
Throwable::printStackTrace,
() -> System.out.println("completed without a value")
);
它工作正常并打印 "Hi admin"。但这不是重点,文章说"In a WebFlux application the subscriberContext
is automatically setup using ReactorContextWebFilter
"。所以我应该能够获取登录的用户。
我有这样的配置:
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class SecurityConfig {
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
return http.authorizeExchange()
.anyExchange().authenticated()
.and().formLogin()
.and().build();
}
@Bean
public MapReactiveUserDetailsService userDetailsService() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
UserDetails admin = User.withDefaultPasswordEncoder()
.username("admin")
.password("password")
.roles("ADMIN")
.build();
return new MapReactiveUserDetailsService(user, admin);
}
}
我是不是漏掉了什么?如果我在 ReactorContextWebFilter 中放置断点,我可以看到它在每个请求之前被正确调用。但是我的 ReactiveSecurityContextHolder 总是空的...
您必须 return 您要访问的流 ReactiveSecurityContextHolder。您不能在另一个流中订阅 或 您必须手动执行 Reactor 上下文切换。
@Component
class Handler {
Mono<ServerResponse> all(ServerRequest request) {
return ReactiveSecurityContextHolder.getContext()
.switchIfEmpty(Mono.error(new IllegalStateException("ReactiveSecurityContext is empty")))
.map(SecurityContext::getAuthentication)
.map(Authentication::getName)
.flatMap(s -> Mono.just("Hi " + s))
.doOnNext(System.out::println)
.doOnError(Throwable::printStackTrace)
.doOnSuccess(s -> System.out.println("completed without value: " + s))
.flatMap(s -> ServerResponse.ok().build());
}
}