Play 2.2 EssentialAction с фьючерсами

Я пытаюсь реализовать механизм аутентификации, аналогичный этому примеру:

    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?


person James Cowhen    schedule 18.02.2014    source источник


Ответы (2)


Iteratee.flatten идет от Future[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)
}
person johanandren    schedule 19.02.2014
comment
Я получаю found : scala.concurrent.Future[play.api.libs.streams.Accumulator[akka.util.ByteString,play.api.mvc.Result]], required: scala.concurrent.Future[play.api.libs.iteratee.Iteratee[?,?]]... возможно, я что-то упускаю (не совсем правильно)! - person Andy Hayden; 06.09.2017

Вы можете использовать ActionBuilder, так как метод invokeBlock возвращает Future[SimpleResult], чтобы вы могли flatMap ваше будущее в вызов базового блока

Что-то типа

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()
    }        
}

}

где AuthenticatedRequest — ваш тип запроса, который обертывает ваш объект сеанса

person Seb Cesbron    schedule 19.02.2014
comment
Обратите внимание, что между Action и EssentialAction есть важное различие, а именно то, что Action всегда будет анализировать тело запроса, в то время как EssentialAction позволяет вам выйти из строя после получения заголовков запроса, игнорируя тело. Это может быть важно, например, для защиты от DoS-атак. - person johanandren; 19.02.2014