Play Framework多租户过滤器

时间:2013-10-07 21:51:13

标签: java scala playframework playframework-2.0 playframework-2.2

我正在尝试使用Play Framework 2.2构建多租户应用程序并遇到了问题。我想在全局onRouteRequest(或Java中的onRequest)中设置一个会话密钥,用于标识用户请求的域的站点ID。在几十个其他框架中,这种类型的东西是无痛的(例如Django),但我知道Play中的会话对象显然是不可变的。

所以,现在,我有这样的事情:

override def onRouteRequest(request: RequestHeader): Option[Handler] = {
    if (request.session.get("site").isEmpty){   
      val id = models.Site.getSiteUIDFromURL(request.host.toLowerCase()).toString()
      if (!id.isEmpty){
       //what goes here to set the session?
      }else{
        //not found - redirect to a general notFound page
      }
    }
    super.onRouteRequest(request)
  }

而且,虽然它不是使用数据库查找的最有效方式,但它现在可用于测试。我需要能够在全局设置会话密钥,但我完全不知道如何做到这一点。如果有更好的方法,我全都耳朵(可能包裹我的控制器?)。

我对Java或Scala中的解决方案示例持开放态度。

1 个答案:

答案 0 :(得分:7)

将Play中的操作视为函数调用,输入是请求,输出是结果。如果要更改包装函数调用的结果,则必须先调用该函数,然后应用更改。向会话添加密钥会更改结果,因为会话将在会话cookie中发送到客户端。在上面的代码中,您在尝试更改结果之前尝试进行更改,即在调用super.onRouteRequest之前。

如果您根本不需要修改路由,请不要在onRouteRequest中执行此操作,在过滤器中执行此操作,更容易。但假设您确实需要修改路由,那么您需要将过滤器应用于返回的处理程序。这就是它的样子:

override def onRouteRequest(request: RequestHeader): Option[Handler] = {
  val maybeSite: Option[String] = request.session.get("site").orElse {
    // Let's just assume that getSiteUIDFromUrl returns Option[String], always use Option if you're returning values that might not exist.
    models.Site.getSiteUIDFromURL(request.host.toLowerCase())
  }

  maybeSite.flatMap { site =>
    super.onRouteRequest(request).map {
      case e: EssentialAction => EssentialAction { req =>
        e(req).map(_.withSession("site" -> site))
      }
      case other => other
    }
  }
}

检查CSRFFilter的源代码,以查看如何在过滤器中向会话添加内容的示例。