我有一个返回Future这样的方法......
def isTokenExpired(token: String): Future[Boolean] = {
...
}
Run Code Online (Sandbox Code Playgroud)
...然后我有另一个调用方法isTokenExpired返回Boolean如下:
def isExpired(token: String): Boolean = {
var result = true
isTokenExpired(token).onComplete {
case Success(r) => result = r
case Failure(_) => result = true
}
result
}
Run Code Online (Sandbox Code Playgroud)
有没有更好的方法来编写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 */ }
}
Run Code Online (Sandbox Code Playgroud)
如您所见,除了到期信息之外,所有jwt属性都是自包含的.方法isExpired使用ReactiveMongo,它总是返回一个Future.为了使事情变得更复杂,我在这样的定制中使用这个jwt Action:
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))
}
}
}
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,我需要返回一个Future[play.mvc.results.Result],而不是Future[Boolean]像isExpired我使用的那样返回Future.map.你明白了吗?
你写的函数不会像你想象的那样工作.它(可能)首先返回true并稍后设置result变量.
通常你会做这样的事情:
isTokenExpired(token).map { result =>
// do stuff
}
Run Code Online (Sandbox Code Playgroud)
在像Play这样的框架中,您可以将其映射Future到http响应并给予播放Future[SimpleResult].Play知道如何处理Future结果.
一般情况下,建议您不要等待a Future完成生产代码,而是使用中的值Future并让您使用的框架处理结果.
在测试中,等待结果可能会派上用场,你可以这样做:
Await.result(someFuture, 5.seconds)
Run Code Online (Sandbox Code Playgroud)
编辑
我可能会提取令牌的构造,以便我最终得到一个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
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
9624 次 |
| 最近记录: |