3

我正在嘗試使用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中的解決方案示例。

回答

6

將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看到如何在過濾器的東西添加到會話的例子。

+0

這很好,謝謝。我要去嘗試一下。直到現在,我只是使用設置會話值的動作組合包裝我的控制器。過濾器看起來非常強大 - 我只希望有更多的文檔。再次感謝。 –