2017-03-09 13 views
1

マルチテナントを含むSaaS製品用のRESTful APIを構築する方法を理解しようとしています。テクノロジースタックは、SpringとHibernateを使用するJavaであり、WARをTomcatにデプロイします。SpringとHibernateとTomcatを使用してステートレス環境でマルチテナントを実装する

私の主な問題は、アプリケーションがCRUDを実行するときに正しいデータベース接続を使用するために、REST呼び出し内でtenant_idをどのように維持するかです。 Tomcatがスレッドプールを使用し、ThreadLocalを使用すべきでないスレッドを再利用していることが分かります。

私は、slf4jがこれをMDCのロギングの実装でサポートしていると読んでいます。サーブレットフィルタは、tenant_idを最前面に維持し、フィルタの終了時にそれをクリアします。したがって、ロガーはメッセージ内の正しいtenant_idを使用します。

同時に、ThreadLocalを使用すると、状態が暗黙的に追加されるため、ステートレスの原則に反します。

さらに、tenant_idを保持している何らかの種類のContextSessionオブジェクトを作成して渡すという考えは、私の問題を解決してくれないようです。このオブジェクトはDALとDAOのレイヤーに渡され、オブジェクトをロードします。私はこのContextSessionクラスのこの高い結合を避け、多くのメソッドシグネチャにそれを含める必要があります。

ステートレス環境でマルチテナントを実装するにはどうすればよいですか?

答えて

0

ユーザーがアプリケーションにログオンすると、何らかの形でテナントに関連付けられます。テナント情報は、SpringのSecurityContextからアクセス可能である必要があります。

例として、2人のテナントがいるアプリケーションがある場合。テナントAとテナントB。ログオンすると、ユーザーはどのテナントに所属しているかを明示する必要があります。これは、さまざまなホスト名(tenantA.myapp.com、tenantB.myapp.comなど)またはURLパラメータの使用、テナント情報のログオンフォームへの入力など、さまざまな方法で実行できます。ユーザーを認証するときは、特定のテナントに関連付けられている認証領域を使用する必要があります。認証の一環として、Spring SecurityContextは、ユーザからの後続のサービス呼び出しでユーザが属するテナントを判断できるようにする情報を含むように設定する必要があります。セキュリティコンテキストは、アプリケーションのさまざまなサービスレイヤからアクセスできるようにする必要があります。そのためには、何かを明示的にプログラムする必要はありません。

+0

ありがとうございました。ですからDAOでは、どのようにしてユーザのtenant_idにSecurityContexを注入しますか?私はその範囲がセッションであると思いますか? –

+0

SecurityContextにアクセスする方法についてはhttp://www.baeldung.com/get-user-in-spring-securityを参照してください。 – httPants

+0

また、SecurityContextは必ずしもセッションスコープである必要はありません。ステートレスセッションでoauth2のようなものを使用すると、リクエストで使用されたトークンはsecuritycontextに格納され、レルム情報(テナントに伝える)が含まれます。 – httPants

0

現在のHttpSessionを特定のテナントに関連付けるさまざまな方法があります。

  1. 一元化共通クライアントのデータベースを介して指定されたバックエンドtenantをルックアップ逆に使用されているURLにclient_idパラメータのいくつかの種類を提供します。

  2. 認証されたユーザーを特定のtenantに関連付けます。ユーザーが集中ユーザーデータベースに対して認証すると、ユーザーアカウントに基づいてテナントが検索されます。そのtenant_idが低くアプリケーション層に渡され、どのように

本当に好みの問題です。

私の最初の選択肢はThreadLocalです。すでにSpring Securityを使用している場合は、すでにThreadLocalの変数を使用しており、それを意識していないことさえあります。

ThreadLocal変数を使用しても、アプリケーションのステートレスなデザインは損なわれません。変数には、使用する必要がある特定の値が含まれることを期待するコードがあります。これは、実際にメソッドシグネチャの引数として明示的に渡すことなく、アプリケーション層全体に状態を渡すための素晴らしい方法です。

明らかに他の2つのオプションは、Contextオブジェクトを使用するか、単に値を直接下流に渡すことです。 Webアプリケーションで

、私は通常、リクエストごとにリクエストパラメータclient_idをルックアップうとtenantId関連すると特別なThreadLocal変数であることを設定しますいくつかの迎撃やフィルタを介してこれを行うだろう。

chain.doFilter(request, response);への呼び出しが返されたり、例外がスローされたりすると、ThreadLocal変数をクリアするだけです。

関連する問題