Play Framework多租户filter

我正在尝试使用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中的解决方案示例持开放态度。

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

如果你根本不需要修改路由,那么不要在onRouteRequest执行此操作,在filter中执行此操作,在那里更容易。 但假设您确实需要修改路由,那么您需要将filter应用于返回的处理程序。 这可能是这样的:

 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的源代码,以查看如何在filter中向会话添加内容的示例。