2017-06-19 35 views
3

私はEntity Frameworkベースのアプリケーションの共有データベースにストアデータを分離するために取り組んでいます。私はSQL Server 2016行レベルのセキュリティを使用したいが、私はすべてのデータベース接続が単一のユーザーを使用することを望むだろう。だから、すべてのEntity Frameworkクエリのストア番号にSQL Server CONTEXT_INFOを設定します。次に、行がCONTEXT_INFOに設定されているストア番号に属しているかどうかをRLSが判断できます。Entity Framework接続でCONTEXT_INFOを設定する方法

これを達成するための唯一のアイデアは、DbContextコンストラクターを更新して、接続自体を作成し、ベースコンストラクターに接続を渡す前にSET CONTEXT_INFOステートメントを実行することです。私はそれを行うために私のDbContextの部分クラスにコンストラクタのオーバーロードを追加するか、元のコンストラクタをそのように生成するためにt4テンプレートを変更することができると思います。

これを行うにはEFが適していますか?私はまずDBを使用しています。

+2

['SESSION_CONTEXT'](https://docs.microsoft.com/en-us/sql/t-sql/functions/session-context-transact-sql)は、複数の値を保持するため、優れています(衝突を避ける(CONTEXT_INFOの生のバイトよりも安全な変換を可能にする)バリエーションを格納し、最初の呼び出しの後に値を読み取り専用として設定できるようにします(セキュリティを強化します)。問題は同じままです(接続が開いた後に 'sp_set_session_context'を実行します)。 –

+0

クール、それを指摘してくれてありがとう! – xr280xr

+0

@ JeroenMostertなぜcontext_infoは他のアプリケーションと衝突するのですか?私たちがcontext_infoを設定するたびに、MARSでも問題はなかったと思います。session_contextのドキュメントでは、「SESSION_CONTEXTのMARSの動作はCONTEXT_INFOの動作と似ています。 –

答えて

1

IDbConnectionInterceptorの実装者のように、接続を開くたびにいくつかのコードを実行できるようです。これにより、ストアドプロシージャを実行してCONTEXT_INFOまたはSESSION_CONTEXT変数を設定することができます。私のインターセプタは、次のようになります。これは、データ層のクラスライブラリであるため

public class MAContextInterceptor : IDbConnectionInterceptor 
{ 
    private static ITenantIDProvider _tenantIDProvider; 
    public MAContextInterceptor(ITenantIDProvider tenantIDProvider) 
    { 
     _tenantIDProvider = tenantIDProvider; 
    } 

    public void Opened(DbConnection connection, DbConnectionInterceptionContext interceptionContext) 
    { 
     // Set SESSION_CONTEXT to current tenant ID whenever EF opens a connection 
     try 
     { 
      Guid tenantID = _tenantIDProvider == null ? Guid.Empty : _tenantIDProvider.GetTenantID(); 

      if (tenantID != Guid.Empty) 
      { 
       DbCommand cmd = connection.CreateCommand(); 
       cmd.CommandText = "ma_setcontextinfo"; 
       cmd.CommandType = System.Data.CommandType.StoredProcedure; 
       DbParameter param = cmd.CreateParameter(); 
       param.ParameterName = "@tenantID"; 
       param.Value = tenantID; 
       cmd.Parameters.Add(param); 
       cmd.ExecuteNonQuery(); 
      } 
     } 
     catch (System.NullReferenceException) 
     { 
      //log error 
     } 
    } 
} 

、私は上記の層は、テナントIDを提供実装を提供することを可能にするITenantIDProviderを追加しました。最終的には、アプリケーションが起動するときにGlobal.asaxに設定されます。また、迎撃器を登録するためにSystem.Data.Entity.Infrastructure.Interception.DbInterception.Add(new MAContextInterceptor(tenantIDProvider));を呼び出します。

私はbeing problematicを見ることができるすべてのDbContextに適用されるようですが、私の目的のためにはこれが機能します。 This pageかなり徹底的に綴っています。私はこの質問をする前に、なぜ私の検索でそれが出てこないのか分かりません!

1

sp_set_session_contextを実行する必要があるだけでなく、DbContextライフサイクルの間、接続を強制的に開いたままにする必要があります。 DbContextが開いている接続で構築されていない場合、実行する必要があります。

db.Database.Connection.Open();

EFが接続プーリングを使用しないようにします。

いいえ、EFではこれを行うための方法はありません。

上記のオプションに加えて、中央のDbContextファクトリメソッドがあります。これは、接続文字列を変更する必要がある場合、またはフェデレーションされた(シャードされた)バックエンドに接続する必要がある場合によく行われます。例:

public static MyDbContext Connect(文字列ユーザー名、bool読み取り専用) { 。 。 。 }

+0

あなたのご意見ありがとうございます。これは正しい方向に私を動かしました。私は作成時にDbContextへのオープンな接続を渡すことができるでしょうが、私は本当に何もしないようにしたり、接続プーリングを防ぎたくありませんでした。私が本当にやりたいことは、接続が開かれるたびにコマンドを実行することだけです。そして私はそれを行う方法を見つけたと思う(私の答えを見てください)。 – xr280xr

関連する問題