2017-03-09 86 views
1

我想了解如何爲涉及多租戶的SaaS產品構建RESTful API。技術棧是使用Spring和Hibernate的Java,並將WAR部署到Tomcat。在使用Spring和Hibernate和Tomcat的無狀態環境中實現多租戶

我的主要問題是我們如何維護REST調用中的tenant_id,以便應用程序在執行CRUD時使用正確的數據庫連接。看到Tomcat使用線程池並重用線程,我們不應該使用ThreadLocal。

我讀過slf4j支持MDC實現進行日誌記錄。 servelet過濾器會保留tenant_id,並在過濾器退出時將其清除。因此,記錄器在消息中使用正確的tenant_id。

同時使用ThreadLocal違背了無狀態原則,因爲這隱含地增加了一個狀態。

此外,創建某種持有tenant_id並傳遞它的ContextSession對象的想法似乎不能解決我的問題。因爲這個對象將傳遞給DAL和DAO的層來加載對象。我想避免在這個ContextSession類上的這種高度耦合,以及不得不將它包含在許多方法簽名中。

如何在無狀態環境中實現多租戶?

回答

0

當用戶登錄到您的應用程序時,它們會以某種方式與租戶關聯。所以租戶信息應該可以從Spring SecurityContext獲取。

作爲一個例子,如果我有一個應用程序與2租戶; tenantA和tenantB。登錄時,用戶需要指出他們屬於哪個租戶。這可以通過各種方式完成,例如使用不同的主機名(例如tenantA.myapp.com,tenantB.myapp.com)或url參數,或在登錄表單中輸入租戶信息。在對用戶進行身份驗證時,您需要使用與特定租戶關聯的身份驗證領域。作爲身份驗證的一部分,應該設置Spring SecurityContext以包含一些信息,通過該信息可以確定用戶在後續服務調用中屬於哪個租戶。應該可以從應用程序的不同服務層訪問SecurityContext,而無需爲此發生任何明確的程序設計。

+0

謝謝。所以在DAO中,我將如何爲用戶的tenant_id注入SecurityContex?我認爲其範圍將會議? –

+0

查看http://www.baeldung.com/get-user-in-spring-security,瞭解有關如何訪問SecurityContext的想法 – httPants

+0

另外,SecurityContext不一定必須是會話作用域。如果你使用類似oauth2的無狀態會話,請求中使用的令牌將存儲在securitycontext中幷包含領域信息(它將告訴你租戶)。 – httPants

0

有多種方法可將您當前的HttpSession與特定租戶相關聯。

  1. 上,用於反向通過集中式通用客戶端數據庫查找指定的後端tenant的URL提供某種類型client_id參數。

  2. 將經過身份驗證的用戶與特定的tenant關聯。當用戶通過集中用戶數據庫進行身份驗證時,會根據用戶帳戶查找租戶。

tenant_id如何傳遞到較低的應用程序層是一個真正的品味問題。

我的第一個選擇是使用ThreadLocal。如果你已經在使用Spring Security,你已經在使用ThreadLocal變量,甚至可能不知道它。使用ThreadLocal變量不會破壞應用程序的無狀態設計。你只是有一段代碼需要一個變量來包含它必須使用的特定值。這只是一種在你的應用程序層中傳遞狀態而不實際顯式地將它作爲參數傳遞給方法簽名的方式。

顯然其他兩個選擇是使用一些上下文對象或僅僅直接傳遞值。

在Web應用程序中,我通常會通過一些攔截器或過濾器,爲每個請求查找請求參數client_id並得到相關tenantId,並設置在一個特殊的ThreadLocal變量做到這一點。

一旦呼叫chain.doFilter(request, response);已返回或引發異常,您只需清除ThreadLocal變量。