【问题标题】:logging an encoded (Bcrypt) password Mono<String> with org.slf4j.Logger from a db call使用 org.slf4j.Logger 从 db 调用记录编码的(Bcrypt)密码 Mono<String>
【发布时间】:2022-01-26 22:21:13
【问题描述】:

我正在尝试弄清楚如何使用 slf4j 记录 Mono&lt;String&gt; 密码,但它总是会返回 Monotype。

logger.info(login.getPassword()+" "+userRepository.findPasswordByUsername(login.getUsername()));

logger.info(login.getPassword()+" "+userRepository.findPasswordByUsername(login.getUsername()).toString());

上面的前 2 次日志记录尝试 返回文字 password(来自请求)和 MonoNext

而且你不能使用.block()

只是抛出

"block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-3"

是的,我知道我可以为 onNext() 传递订阅者/消费者,例如:

.subscribe(x -> System.out.println( x.toString()))

要获得一些输出,但我将如何仅使用记录器来做到这一点,有没有办法?

login 表示从请求中检索到的用户。 密码事先被正确存储和编码(Bycrypt)(似乎不是问题)。

编辑:提供更多上下文 userRepository.findPasswordByUsername("username") 将返回一个我想与另一个密码进行比较的 Mono:

passwordEncoder.matches( "userinputPW", userRepository.findPasswordByUsername("username") )

这就是你在 Spring 中使用 ByCryptEncoder 的方式,我不能 .map() 将 Mono 转换为字符串(显然总是会返回一个对象,而不是这里解释的字符串 https://stackoverflow.com/a/47180610/6414816

使用 spring-boot-starter-webflux、spring-boot-starter-data-r2dbc、spring-boot-starter-security

我错过了什么?提前致谢。

【问题讨论】:

  • 您的密码表示为 Mono 类而不是字符串。通过在互联网上的快速搜索,Mono 是一个 0..1 元素的流,您可以尝试 login.getPassword().block() 来获取字符串值虽然这可能有效,但我建议您阅读有关 Mono 、 Flux 的更多信息, java 反应式编程

标签: java spring spring-boot spring-security spring-webflux


【解决方案1】:

这是正确的,您不应该在反应式应用程序中阻塞,也不应该在这种用户情况下订阅,因为您的应用程序很可能是生产者,而调用客户端是订阅的消费者。

您正在寻找的是处理side effectsdoOn 运算符。日志记录是一个side effect,它是您想要在不干扰当前流程的情况下做的事情。例如更新一些东西,增加一些东西,或者在你的情况下写入日志。

你想要的操作系统可能是doOnSuccess 运算符

示例(自从我在移动设备上使用以来,我没有使用过编译器),但类似这样。

function Mono<Login> foobar(Login login) {
    return userRepository.findPasswordByUsername(login.getUsername)
                .doOnSuccess(pwd -> {
                    logger.info(login.getPassword() + " " + pwd);
                }).thenReturn(login);
}

【讨论】:

  • 我认为这应该是一个回调?任何像 .doOnNext() 这样的“副作用”调用也只会返回一个对象 .thenReturn("Value") 只会在 Mono 为记录器和 db 调用完成后发出“Value”。
  • 这是一个问题吗?我不明白你的说法
  • 你的 sn-p 基本上就是我正在尝试的,doOnSucceed() 或 doOnNext() 也会等待 Mono。你必须订阅()这工作:public Disposable foobar(User login) { Mono&lt;String&gt; userMono = userRepository.findPasswordByUsername(login.getUsername()); return userMono.subscribe(x -&gt; logger.info("password: "+x));}我在logger.info("password: "+userRepository.findPasswordByUsername(login.getUsername()).share().block().toString() );(编译器对此很好,并且在运行时没有抛出异常)虽然不是很优雅但它有效。
  • 正如我所写的......你还没有透露是谁发起的电话。如果这是一个 webflux 服务,并且您有一个调用端点的网页,该网页是订阅者,所以您不调用订阅,您将单声道返回给客户端,框架将处理订阅。另一方面,如果您的代码正在消耗其他东西,也就是。您的应用程序发起对另一个服务的调用,而您的应用程序是最终消费者,那么您必须调用 subscribe。我假设第一种情况
  • 请记住,如果您只发布一行代码,您将得到一个做出某些假设的答案。如果您提供了一个没有完整上下文的糟糕问题,我们将根据您提供的信息给出答案。
【解决方案2】:

由于还没有人想出答案,

logger.info("userName :" +userMono.map(user -> user.getUsername()).share().block());

.share() 将允许.block()

来自文档: “准备一个与 Flux.shareNext() 类似的共享此 Mono 结果的 Mono。当第一个订阅者使用 subscribe() API 订阅时,这将有效地将此 Mono 变成一个热门任务。进一步的订阅者将共享相同的订阅,因此相同的结果.值得注意的是,这是一个不可取消的订阅。” 对我有用(即使它包含 .block()

userMono.subscribe(user -> logger.info("username: "+user.getUsername()));

将返回Disposable

两者都会为记录器输出String 值。

在旁注(我不知道)上有一个运算符 .log("callerForADefinedLogger")。

【讨论】:

    猜你喜欢
    • 2019-10-26
    • 1970-01-01
    • 2016-07-25
    • 2017-12-13
    • 1970-01-01
    • 2018-08-25
    • 1970-01-01
    • 2020-09-03
    • 2016-09-28
    相关资源
    最近更新 更多