Spring 在Kotlin流中使用ReactiveSecurityContextHolder
我正在使用Kotlin进行SpringBoot(2.2)项目,CouchDB作为(反应式)数据库,结果是异步DAO(挂起函数或返回流的函数)。我试图设置WebFlux,以便也有异步控制器(同样,我希望返回流,而不是Flux)。但是我在从Spring 在Kotlin流中使用ReactiveSecurityContextHolder,spring,spring-boot,kotlin,spring-webflux,kotlin-coroutines,Spring,Spring Boot,Kotlin,Spring Webflux,Kotlin Coroutines,我正在使用Kotlin进行SpringBoot(2.2)项目,CouchDB作为(反应式)数据库,结果是异步DAO(挂起函数或返回流的函数)。我试图设置WebFlux,以便也有异步控制器(同样,我希望返回流,而不是Flux)。但是我在从ReactiveSecurityContextHolder检索安全上下文时遇到问题 据我所知,与使用ThreadLocal存储它的SecurityContextHolder不同,ReactiveSecurityContextHolder依赖于这样一个事实,Spri
ReactiveSecurityContextHolder
检索安全上下文时遇到问题
据我所知,与使用ThreadLocal
存储它的SecurityContextHolder
不同,ReactiveSecurityContextHolder
依赖于这样一个事实,Spring在订阅我的反应链时,也将该上下文存储在该链中,因此,允许我从链中调用ReactiveSecurityContextHolder.getContext()
问题是,我必须在某个时候将我的Mono
转换为流,这使我失去了SecurityContext
。所以我的问题是:有没有一种方法可以让Spring引导控制器在从我的逻辑中的ReactiveSecurityContextHolder
检索安全上下文时返回流?基本上,经过简化后,应该是这样的:
@GetMapping
fun getArticles(): Flow<String> {
return ReactiveSecurityContextHolder.getContext().flux().asFlow() // returns nothing
}
@GetMapping
fun getArticles():流{
return ReactiveSecurityContextHolder.getContext().flux().asFlow()//不返回任何内容
}
请注意,如果我直接返回通量(跳过.asFlow()
),或者在最后添加.single()
或.toList()
(因此使用suspend fun
),那么它可以正常工作,并且返回安全上下文,但这不是我想要的。我猜解决方案是将上下文从流量(从ReactiveSecurityContextHolder
的初始反应链)转移到流,但默认情况下似乎没有这样做
编辑:下面是一个示例项目,展示了这个问题:您真正想要实现的是从流内部访问您的ReactorContext 实现这一点的一种方法是放松返回流的需要,转而返回通量。这允许您恢复ReactorContext,并将其传递给将用于生成数据的流
@ExperimentalCoroutinesApi
@GetMapping("/flow")
fun flow(): Flux<Map<String, String>> = Mono.subscriberContext().flatMapMany { reactorCtx ->
flow {
val ctx = coroutineContext[ReactorContext.Key]?.context?.get<Mono<SecurityContext>>(SecurityContext::class.java)?.asFlow()?.single()
emit(mapOf("user" to ((ctx?.authentication?.principal as? User)?.username ?: "<NONE>")))
}.flowOn(reactorCtx.asCoroutineContext()).asFlux()
}
@experimentalRoutinesAPI
@GetMapping(“/flow”)
fun flow():Flux=Mono.subscriberContext().flatMapMany{reactorcx->
流动{
val ctx=coroutineContext[ReactorContext.Key]?.context?.get(SecurityContext::class.java)?.asFlow()?.single()
emit(将(“用户”映射到((ctx?.authentication?.principal as?user?.username?:“”))中)
}.flow(reactorcx.asCoroutineContext()).asFlux()
}
在需要从挂起方法访问ReactorContext的情况下,只需从coroutineContext获取它,无需进一步技巧:
@ExperimentalCoroutinesApi
@GetMapping("/suspend")
suspend fun suspend(): Map<String,String> {
val ctx = coroutineContext[ReactorContext.Key]?.context?.get<Mono<SecurityContext>>(SecurityContext::class.java)?.asFlow()?.single()
return mapOf("user" to ((ctx?.authentication?.principal as? User)?.username ?: "<NONE>"))
}
@experimentalRoutinesAPI
@GetMapping(“/suspend”)
suspend fun suspend():映射{
val ctx=coroutineContext[ReactorContext.Key]?.context?.get(SecurityContext::class.java)?.asFlow()?.single()
将mapOf(“用户”返回到((ctx?.authentication?.principal as?user?.username?:“”)
}