当前位置: 首页 > 知识库问答 >
问题:

reactiveSecurityContextHolder.getContext()为空,但@AuthenticationPrincipal有效

宣熙云
2023-03-14
SecurityContextHolder.getContext().getAuthentication();
ReactiveSecurityContextHolder.getContext().map(ctx -> ctx.getAuthentication()).block()

试图从控制器或组件访问这些代码将解析为null。我有些怀疑我是否真的在自定义管理器中返回了身份验证实例,看起来我是:

@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();
}

其中PreAuthenticationTokenAbstractAuthenticationTokenAuthenticationToken扩展UsernamePasswordAuthenticationToken的实例

有趣的是,尽管reactiveSecurityContextHolder.getContext().map(ctx->ctx.getAuthentication()).block()不能在控制器中工作,但我可以将身份验证主体与@AuthenticationPrincipal注释作为方法参数成功地注入控制器中。

这似乎是一个配置问题,但我不知道在哪里。有人知道为什么我不能返回身份验证吗?

共有1个答案

郝修为
2023-03-14

由于您使用的是WebFlux,所以您使用事件循环处理请求。您不再像Tomcat那样使用每个请求的线程模型。

身份验证是按上下文存储的。

使用Tomcat,当请求到达时,Spring将身份验证存储在SecurityContextholder中。SecurityContexTholder使用ThreadLocal变量存储身份验证。只有当您试图从设置特定身份验证对象的同一线程中的ThreadLocal对象获取该对象时,特定身份验证对象才对您可见。这就是为什么您可以通过静态调用在controller中获得身份验证。ThreadLocal对象知道要返回给您什么,因为它知道您的上下文--您的线程。

返回一个reactive-chain from方法,即发出reactiveSecurityContextHolder.getContext()调用。

因为您返回的是一个反应操作符链,所以Spring会对您的链进行订阅,以便执行它。当Spring这样做时,它为整个链提供了一个安全上下文。因此,该链中的每个reactiveSecurityContextHolder.getContext()调用都将返回预期的数据。

您可以在这里阅读更多关于单核/通量上下文的信息,因为它是Reactor特有的特性。

 类似资料:
  • 问题内容: 我一直在Spring Security + Webflux中使用ReactiveAuthenticationManager。它是经过自定义的,以返回一个实例,从该实例中我可以确定是调用时应接收的内容。据我所知,我无法通过两种方式访问​​身份验证上下文: 要么 尝试从控制器或组件访问这些文件将解决。对于我是否真的要在自定义管理器中返回实例,我有些疑问,好像我是: 和的实例在哪里扩展 有趣

  • 问题内容: 我有以下代码: 不,我检查了myLines的内容,这些是正确的。 另外,我得到的印刷品会尽可能频繁地打印“完成”。csv已创建。 但是,如果我手动打开它,它是空的。 这可能是什么原因? 问题答案: 您从不刷新缓冲区或关闭BufferedWriter。 在for循环之后,进行以下调用: 即使有其他资源,在完成后关闭它们也是一个好主意。

  • 我只是想用JS向服务器发送一个请求。但服务器具有空的数组。我可以使用,但在PHP5.6中将不推荐使用它。我可以在数组中发布数据吗? 环境:Chrome、apache2、PHP、AngularJS(我正在使用函数)。 调试映像(很抱歉没有直接附加映像--我没有10信誉)

  • 如上图, 是el-table渲染出来的, img 的src 是由后台提供的: ORIGINALLOGO会为空, 但是却有不同的处理, 一个是图片加载失败的icon, 一个却直接是空的, img 渲染的结果是一样的: 请问各位大佬为什么会有这种情况发生呀, 具体原因是什么呢?

  • 我有一个Spring项目,它使用sping-oaust2和sping-Security使用LDAP身份验证提供程序进行身份验证。 在控制器中,我可以使用< code > @ AuthenticationPrincipal 注释访问当前主体的< code>UserDetails。 然而,当我使用client_credential令牌到达endpoint时,是一个,它是OAuth客户端id。sprin

  • 当我尝试从前端登录时,我遇到了一个错误。我可以注册,但我不能登录。 错误: Java语言lang.NullPointerException:无法调用“com.app.auction.user.user.getName()”,因为“user”在com上为null。应用程序。拍卖使用者UserVM。(UserVM.java:17)~(classes/:na)位于com。应用程序。拍卖授权。AuthCo