我一直在Spring Security + Webflux中使用ReactiveAuthenticationManager。它被定制为返回一个UsernamePasswordAuthenticationToken
的示例,从我可以告诉的是,当我调用ReactiveSecurityContextHolder.getContext().map(ctx -> ctx.getAuthentication()).block()
时,我应该接收到的。据我所知,我无法通过以下两种方式访问身份验证上下文:
SecurityContextHolder.getContext().getAuthentication();
或
ReactiveSecurityContextHolder.getContext().map(ctx -> ctx.getAuthentication()).block()
而试图从控制器或组件访问这些文件则会解析为null
。我怀疑我是否真的在我的自定义管理器中返回了一个Authentication
示例,看起来我是这样做的:
@Override
public Mono<Authentication> authenticate(final Authentication authentication) {
if (authentication instanceof PreAuthentication) {
return Mono.just(authentication)
.publishOn(Schedulers.parallel())
.switchIfEmpty(Mono.defer(this::throwCredentialError))
.cast(PreAuthentication.class)
.flatMap(this::authenticatePayload)
.publishOn(Schedulers.parallel())
.onErrorResume(e -> throwCredentialError())
.map(userDetails -> new AuthenticationToken(userDetails, userDetails.getAuthorities()));
}
return Mono.empty();
}
其中PreAuthentication
是AbstractAuthenticationToken
的instance,AuthenticationToken
扩展UsernamePasswordAuthenticationToken
有趣的是,尽管ReactiveSecurityContextHolder.getContext().map(ctx -> ctx.getAuthentication()).block()
在控制器中不起作用,但我可以在控制器中成功地将带有@AuthenticationPrincipal
注解的身份验证主体作为方法参数注入。
这似乎是一个配置问题,但我不知道在哪里。有人知道为什么我不能返回验证吗?
5条答案
按热度按时间wbrvyc0a1#
由于您使用的是WebFlux,因此您使用的是事件循环来处理请求。您不再像使用Tomcat那样使用每请求一个线程的模型。
身份验证按上下文存储。
使用Tomcat,当请求到达时,Spring将authentication存储在
SecurityContextHolder
中。SecurityContextHolder
使用ThreadLocal
变量存储身份验证。特定的authentication对象是可见的,只有当你试图从ThreadLocal
对象中获取它时,在同一个线程中,它被设置。这就是为什么你可以通过静态调用在控制器中获得身份验证。ThreadLocal对象知道要返回什么给你,因为它知道你的上下文-你的线程。使用WebFlux,只需一个线程即可处理所有请求。像这样的静态调用将不再返回预期结果:
SecurityContextHolder.getContext().getAuthentication();
因为没有办法再使用ThreadLocal对象了。为您获取身份验证的唯一方法是在控制器的方法签名中请求它,或者...
返回一个reactive-chain from方法,即调用
ReactiveSecurityContextHolder.getContext()
。因为你返回了一个React操作符链,Spring订阅你的链,以便执行它。当Spring这样做时,它为整个链提供了一个安全上下文。因此,该链中的每个调用
ReactiveSecurityContextHolder.getContext()
都将返回预期的数据。你可以在这里阅读更多关于Mono/Flux的内容,因为它是一个特定于Reactor的特性。
iyfjxgzm2#
我也有类似的问题。所以,我上传了我的Github ReactiveSecurityContext与JWT Token示例。
https://github.com/heesuk-ahn/spring-webflux-jwt-auth-example
希望对你有帮助。
我们需要创建一个自定义的
authentication filter
。如果在该过滤器中验证成功,则它将principal
信息存储在ReactiveSecurityHolder
中。我们可以从控制器访问ReactiveSecurityHolder
。h7appiyu3#
今天解决这样的问题在下一个方式:
UserCredential.class
-自定义类,包含userId、姓名首字母、登录名和权限。t2a7ltrp4#
除了Alex Derkach所说的,用更简单的话来说:
将产生无效,因为你正在破坏React堆链。
您可以做的是直接在RestController中返回Mono对象然后您将看到身份验证上下文确实存在。
ix0qys7i5#
如果你想访问一个webfilter中的身份验证对象,你可以这样做。