首页 > 解决方案 > 如何获取默认 BodyParser?

问题描述

我要问的是如何在 2.6中获取Default Scala Play实现。BodyParser但是,如果您知道解决这个用例的更简洁的方法,我很高兴听到它。

一些前言......我重用了一个 Java Play 框架Play-Authenticate (PA) 在上面构建一个Scala Play 应用程序。是的,把我钉在十字架上!我想要所有的社交身份验证功能,但我的应用程序在 Scala 中并使用例如 Slick。是的,是的,我可以尝试在 Scala 中重写 PA,但现在没有时间......不过考虑一下。

现在这已经不碍事了,这是我的用例。我有 Scala 控制器,需要将 Java 上下文传递给 PA 框架才能使用它。我还需要检查用户是否可以通过cookie进行身份验证,即用户第一次登录时是否选中了“记住我”框。这个“解决方案”在迁移到 Play 2.6 之前曾经有效,但现在由于BodyParser.

这就是“汉堡”的样子。我想吃它……我需要通过检查传入的 cookie 来验证用户身份,但同时会创建一个 Java 上下文(与 PA 互操作)。但由于我有可怕的 Java 上下文,我可以在一个请求的范围内使其在整个 Scala 应用程序中可用:

def index =
  TryCookieAuthAction { implicit jContext =>  // <==== this is the burger
    deadbolt.WithAuthRequest()() { implicit request =>
     Future {
        Ok(indexView(userService))
     }
  }
}

现在让我们看看牛。在 2.6 之前它曾经可以工作,因为我没有被迫重写parser,但现在在 2.6 中我被迫:

case class TryCookieAuthAction[A](block: Http.Context => Action[A])(implicit auth: PlayAuthenticate, config: Configuration, env: Environment, mat: Materializer, ec: ExecutionContext) extends Action[A] {
  def apply(request: Request[A]): Future[Result] = {
    val contextComponents = JavaHelpers.createContextComponents(config, env)
    val jContext = JavaHelpers.createJavaContext(request, contextComponents)

    TryCookieAuthAction.jContextDv += (request.id -> jContext)

    if(!auth.isLoggedIn(jContext)) {
      // calling Java here so need a Java Context
      auth.tryAuthenticateWithCookie(jContext)
    }

    val scalaResult: Future[Result] = Await.ready(block(jContext)(request), 60 seconds)

    val session : Seq[(String, String)] = jContext.session().keySet().toArray.map(key => (key.toString, jContext.session().get(key)))
    val cookies : Seq[Cookie] = jContext.response().cookies().asScala.toSeq.map(cookie =>
      Cookie(cookie.name(), cookie.value(), maxAge = Option(cookie.maxAge()), path = cookie.path(), domain = Option(cookie.domain()),
        secure = cookie.secure(), httpOnly = cookie.httpOnly())
    )

    TryCookieAuthAction.jContextDv -= request.id

    scalaResult.map(_.withSession(session : _*).withCookies(cookies : _*))
  }

  override def executionContext = ec

  override val parser: BodyParser[A] = ???
}

object TryCookieAuthAction {
  private lazy val jContextDv = TrieMap[Long, play.mvc.Http.Context]()

  /**
    * Extracts the Java context given a request
    * @param request The request
    * @tparam A The request body type
    */
  implicit class RequestToContext[A](request: Request[A]) {
    def jContextOption : Option[Http.Context] = jContextDv.get(request.id)
    def jContext : Http.Context = jContextDv(request.id)
  }

  def apply[A](action: Action[A])(implicit auth: PlayAuthenticate, config: Configuration, env: Environment, mat: Materializer, ec: ExecutionContext): TryCookieAuthAction[A] = TryCookieAuthAction(_ => action)
}

我的问题是如何获得默认值BodyParser,还是有更聪明的方法来做到这一点?例如,创建一个ActionBuilder我尝试过但我不能jContext隐式地为封闭的Action.

标签: scalaplayframeworkplayframework-2.6

解决方案


我找到了解决方案或潜在解决方案?

首先通过更改object WithJContextSupportAction'apply方法以包含play.api.mvc.PlayBodyParsers为隐式参数:

def apply[A](action: Action[A])(implicit config: Configuration, env: Environment, bodyParsers: PlayBodyParsers, ec: ExecutionContext): WithJContextSupportAction[A] = WithJContextSupportAction(_ => action)

然后将新的隐式更改传播到动作类:

case class WithJContextSupportAction[A](block: JContext => Action[A])(implicit config: Configuration, env: Environment,
                                                                      bodyParsers: PlayBodyParsers, ec: ExecutionContext) extends Action[A] {

最后覆盖parser这样的:

override def parser= bodyParsers.default.asInstanceOf[BodyParser[A]]

推荐阅读