2017-11-08 3 views
0

私のアプリでは、管理者が特定の画面に移動して、特定の役割で特定のコントローラ/メソッドを使用できるようにする機能を追加したいと考えています。 は、今私がASP.NETのカスタムAuthorizeAttributeのスマートキャッシング

[Authorize(Roles = "APUL_Admin")]

のようなビルドでの役割のチェックを使用しているので、私は[AuthorizeExtended()]することを変更し、私はそのようにそれを実装しています:

かなりすべてである
public class AuthorizeExtended : AuthorizeAttribute 
    { 
     protected override bool AuthorizeCore(HttpContextBase httpContext) 
     { 
      var isAuthorized = base.AuthorizeCore(httpContext); 
      if (!isAuthorized) 
      { 
       return false; 
      } 
      // Point of interest **HERE** 

      return true; 
     } 
    } 

標準。

HttpContextBaseのこの瞬間(ここではを参照)私はユーザーの役割とコントローラとメソッドを知っています。そして私はDBに行って、それらの役割がこのコントローラ/アクションにアクセスできるようにすることができます。それは遅いですし、それがDBのためのオーバーヘッドがたくさんあるので、私はすべての要求のためにデータベースに行きたくない :

は、ここに私の問題です。それに対処する最善の方法は何ですか?キャッシュしますか?私は実装の詳細を探しています。

何か助けていただければ幸いです。ありがとうございました!

答えて

2

はい、キャッシュは、DBへの重複した要求を避けるために必要なものです。

internal class CacheKey 
{ 
    public string Role { get; set; } 

    public string Controller { get; set; } 

    public string Method { get; set; } 

    public override bool Equals(Object obj) 
    { 
     CacheKey cmp = obj as CacheKey; 
     if (cmp == null) 
     { 
      return false; 
     } 

     return Role == cmp.Role && Controller == cmp.Controller && Method == cmp.Method; 
    } 

    public override int GetHashCode() 
    { 
     // Overflow is fine, just wrap 
     unchecked 
     { 
      int hash = 17; 
      hash = hash * 23 + Role.GetHashCode(); 
      hash = hash * 23 + Controller.GetHashCode(); 
      hash = hash * 23 + Method.GetHashCode(); 
      return hash; 
     } 
    } 
} 

public class AuthorizeExtended : AuthorizeAttribute 
{ 
    private static ConcurrentDictionary<CacheKey, bool> cache = new ConcurrentDictionary<CacheKey, bool>(); 

    protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
     var isAuthorized = base.AuthorizeCore(httpContext); 
     if (!isAuthorized) 
     { 
      return false; 
     } 
     // Point of interest **HERE** 

     // Looking up in the cache 
     var cacheKey = new CacheKey 
     { 
      Role = role, 
      Controller = controller, 
      Method = method, 
     }; 

     bool authorized; 
     if (cache.TryGetValue(cacheKey, out authorized)) 
     { 
      return authorized; 
     } 

     // Make DB call and get value for authorized 
     // ... 

     // Store 'authorized' value in the cache 
     cache.TryAdd(cacheKey, authorized); 

     return authorized; 
    } 
} 
+0

唯一の制限は、* adminsが特定の画面に移動し、キャッシュが公開されていないため特定の役割*に対して特定のコントローラ/メソッドを使用できるようにすることができないことです。実際の読み込み/書き込み競合がないため、ConcurrentDictionaryはある程度殺すことになります。私はDictionaryを使用し、その値を 'ControllerContext.HttpContext.Application.Item'に格納します。 –

+0

@ CodeFullerねえ、みんな!迅速な対応をありがとう!私はここにいくつかの質問があります:1.私はCacheKeyを使用する必要がありますか?私はちょうど文字列キー=ロール+コントローラ+メソッドを使用できますか? 2.それは愚かな質問ですが、私はその辞書を格納するためにシングルトンが必要なように感じました。 AuthorizeExtended属性のライフサイクルについて何か不足していますか? 3.最後のもの。ユーザーの許可を変更した場合(方法Aへのアクセスが許可されていない場合)、どうすればこの辞書をパージすることができますか?タイムスタンプなどを使用する必要がありますか?ありがとう! –

+0

AuthorizeExtendedクラスのprivate staticメンバではなく、HttpRuntime.Cacheを使用することをお勧めしますか? –

関連する問題