gpt4 book ai didi

Scala:如何获得 Future 的结果

转载 作者:行者123 更新时间:2023-12-04 14:45:05 25 4
gpt4 key购买 nike

我有一个返回 Future 的方法像这样...

def isTokenExpired(token: String): Future[Boolean] = {
...
}

...然后我有另一种调用 isTokenExpired 的方法返回 Boolean像这样:
def isExpired(token: String): Boolean = {
var result = true
isTokenExpired(token).onComplete {
case Success(r) => result = r
case Failure(_) => result = true
}
result
}

有没有更好的方法来写 isExpired方法?

编辑

根据 ECOLOR 的要求,让我为您提供更多详细信息。对于我的 Play 应用程序,我实现了基于 JSON Web Token (jwt) 的授权机制。除了过期时间之外,所有声明都包含在 jwt 中,过期时间存储在 MongoDB 集合中。以下是我的 Token 的总结类看起来像:
class Token {
...

def id: String = { ... }
def issueTime: LocalDateTime = { ... }
def issuer: String = { ... }
...
def isValid: Boolean = { ... }
def isExpired: Boolean = { /* uses ReactiveMongo to access MongoDB */ }
}

如您所见,除过期信息外,所有 jwt 属性都是独立的。方法 isExpired使用 ReactiveMongo,它总是返回 Future .为了让事情变得更复杂,我在定制的 Action 中使用了这个 jwt。像这样:
class SecuredAction[T <: Controller] private(private val methodName: String)
extends ActionBuilder[ApiRequest] {

...

def invokeBlock[A](request: Request[A], block: (ApiRequest[A]) => Future[SimpleResult]) = {{
request.headers.get(HeaderNames.AUTHORIZATION) match {
case Some(header) => s"""$AuthType (.*)""".r.unapplySeq(header).map(_.head.trim)
case _ => None
}} match {
case Some(tokenString) => {
val token = Token(tokenString)

if (!token.isValid) {
Logger.warn(s"request ${request.uri} not authorized: token ${token.id} has been tampered")
Future.successful(Unauthorized(AuthErrors.authenticationViolated(token.subject)(request).asJson))
} else if (token.isExpired) {
Logger.debug(s"request ${request.uri} not authorized: token ${token.id} has expired")
Future.successful(Unauthorized(AuthErrors.authenticationExpired(token.subject)(request).asJson))
} else if (!isAuthorized(token)) {
Logger.info(s"request ${request.uri} not authorized: required claims not defined for account ${token.subject}")
Future.successful(Forbidden(AuthErrors.requestNotAuthorized(token.subject)(request).asJson))
} else {
Logger.debug(s"request ${request.uri} authorized for account ${token.subject}")
block(new ApiRequest(token, request))
}
}
case _ => {
Logger.debug(s"request ${request.uri} not authenticated")
Future.successful(Unauthorized(
AuthErrors.requestNotAuthenticated()(request).asJson
).withHeaders(HeaderNames.WWW_AUTHENTICATE -> AuthType))
}
}
}

如您所见,我需要返回一个 Future[play.mvc.results.Result] ,不是 Future[Boolean]将返回 isExpired如果我使用 Future.map .你明白了吗?

最佳答案

你写的函数不会像你想象的那样工作。它会(可能)首先返回 true然后设置 result多变的。

通常你会做这样的事情:

isTokenExpired(token).map { result =>
// do stuff
}

在像 Play 这样的框架中,您将映射 Future到一个 http 响应并给 Play 回一个 Future[SimpleResult] . Play 懂得处理 Future结果。

一般来说,建议您不要等待 Future在生产代码中完成,但使用 Future 中的值并让您使用的框架处理结果。

在测试中等待结果可能会派上用场,你可以这样做:
Await.result(someFuture, 5.seconds)

编辑

我可能会提取 token 的构造,以便最终得到 Future[Token] .这让我可以更轻松地撰写内容。它还允许我创建具有更好架构且更易于测试的代码。

我可能会将代码分解为更小的方法,但下面的示例让您了解我将采取的方向。
class TokenService(connection: MongoConnection) {

def tokenFor(tokenString: String): Future[Token] = ???
}

class SecuredAction(tokenService: TokenService) extends
ActionBuilder[ApiRequest] {

import play.api.libs.concurrent.Execution.Implicits._

def invokeBlock[A](request: Request[A], block: (ApiRequest[A]) => Future[SimpleResult]) =
extractTokenFrom(request) match {
case Some(tokenString) => {

tokenService.tokenFor(tokenString) flatMap {
case token if (!token.isValid) =>
Logger.warn(s"request ${request.uri} not authorized: token ${token.id} has been tampered")
Future.successful(Unauthorized(AuthErrors.authenticationViolated(token.subject)(request).asJson))
case token if (token.isExpired) =>
Logger.debug(s"request ${request.uri} not authorized: token ${token.id} has expired")
Future.successful(Unauthorized(AuthErrors.authenticationExpired(token.subject)(request).asJson))
case token if (!token.isAuthorized) =>
Logger.info(s"request ${request.uri} not authorized: required claims not defined for account ${token.subject}")
Future.successful(Forbidden(AuthErrors.requestNotAuthorized(token.subject)(request).asJson))
case token =>
Logger.debug(s"request ${request.uri} authorized for account ${token.subject}")
block(new ApiRequest(token, request))
}
}
case _ =>
Logger.debug(s"request ${request.uri} not authenticated")
Future.successful(Unauthorized(
AuthErrors.requestNotAuthenticated()(request).asJson).withHeaders(HeaderNames.WWW_AUTHENTICATE -> AuthType))
}

val AuthType = "MyAuthType"
val TokenHeader = s"""$AuthType (.*)""".r

def extractTokenFrom(request: RequestHeader) = {
val authorizationHeader = request.headers.get(HeaderNames.AUTHORIZATION)
authorizationHeader flatMap {
case TokenHeader(token) => Some(token.trim)
case _ => None
}
}
}

关于Scala:如何获得 Future 的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22900197/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com