Scala:如何获得未来的结果
我有一个像这样返回Future的方法……
def isTokenExpired(token: String): Future[Boolean] = { ... } …然后我有另一个调用isTokenExpired的方法返回一个这样的布尔值: def isExpired(token: String): Boolean = { var result = true isTokenExpired(token).onComplete { case Success(r) => result = r case Failure(_) => result = true } result } 有没有更好的方法来编写isExpired方法? 编辑 根据EECOLOR的要求,让我向您提供更多详细信息.对于我的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],如果我使用Future.map则会返回isExpired.你明白了吗? 解决方法
你写的函数不会像你想象的那样工作.它(可能)首先返回true,然后设置结果变量.
通常你会做这样的事情: isTokenExpired(token).map { result => // do stuff } 在像Play这样的框架中,您可以将Future映射到http响应,并为Play回放一个Future [SimpleResult]. Play知道如何处理Future结果. 通常,建议您不要等待Future在生产代码中完成,而是使用Future中的值并让您使用的框架处理结果. 在测试中,等待结果可能会派上用场,你可以这样做: Await.result(someFuture,5.seconds) 编辑 我可能会提取令牌的构造,以便最终得到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 } } } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |