0

我正在尝试实现类似于此示例的身份验证机制:

    def HasToken(action: String => EssentialAction): EssentialAction = EssentialAction { requestHeader =>
      val maybeToken = requestHeader.headers.get("X-SECRET-TOKEN")
      maybeToken map { token =>
        action(token)(requestHeader) // apply requestHeader to EssentialAction produces the Iteratee[Array[Byte], SimpleResult]
      } getOrElse {
        Done(Unauthorized("401 No Security Token\n")) // 'Done' means the Iteratee has completed its computations
      }
    }

但是,在我的情况下,我将随机令牌值映射到存储在 Mongodb 中的服务器端的会话。目标是能够让用户随意终止他的所有其他会话。

但是,我从 ReactiveMongo 获得的数据将被包装在 Future 中。

我想要这样的东西:

    def HasToken(action: String => EssentialAction): EssentialAction = EssentialAction { requestHeader =>
      val maybeToken = requestHeader.headers.get("session")
      maybeToken map { token =>
        //This returns a future..
        Session.find(session).map { result => 
          result match
            case Some(session) => action(session)(requestHeader)
            case None => Done(Unauthorized())
        }
      } getOrElse {
        Done(Unauthorized("401 No Security Token\n")) // 'Done' means the Iteratee has completed its computations
      }
    }

EssentialAction 可以做到这一点吗?

4

2 回答 2

2

Iteratee.flattenFuture[Iteratee[A, E]] => Iteratee[A, E]所以你可以这样做:

def HasToken(action: String => EssentialAction): EssentialAction = EssentialAction { requestHeader =>
   val maybeToken = requestHeader.headers.get("session")

   val futureIteratee: Future[Iteratee[Array[Byte], SimpleResult]] = maybeToken map { token =>
     //This returns a future..
     Session.find(token).map {
       case Some(session) => action(session)(requestHeader)
       case None => Done[Array[Byte], SimpleResult](Unauthorized("Invalid token"))
     }
   } getOrElse {
     Future.successful(Done[Array[Byte], SimpleResult](Unauthorized("401 No Security Token\n")))
   }

   Iteratee.flatten(futureIteratee)
}
于 2014-02-19T08:55:53.747 回答
1

You can use an ActionBuilder as the invokeBlock method return a Future[SimpleResult] so you can flatMap your future into a call to the underlying block

Something like

object Authenticated extends ActionBuilder[AuthenticatedRequest] {
  def invokeBlock[A](request: Request[A], block: (AuthenticatedRequest[A]) => Future[SimpleResult]) = {
    Session.find(session).map { result => 
      result match
        case Some(session) => block(new AuthenticatedRequest(session))
        case None => Unauthorized()
    }        
}

}

where AuthenticatedRequest is your request type that wraps your session object

于 2014-02-19T08:26:17.687 回答