Play Framework多租户过滤器

3
我在使用Play Framework 2.2构建一个多租户应用程序,并遇到了问题。我希望在全局onRouteRequest(或Java中的onRequest)中设置一个会话键,以标识用户请求的域的站点ID。但是,与其他许多框架不同(例如Django),Play中的 session 对象显然是不可变的,因此这种事情变得非常困难。
因此,现在我有类似以下代码:
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个回答

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的源代码,了解如何在过滤器中向会话添加内容的示例。


太好了,谢谢。我要试一下。到目前为止,我只是使用动作组合来包装我的控制器,设置会话值。过滤器似乎非常强大 - 我只希望有更多的文档资料。再次感谢。 - Michael Hawkins

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接