2017-05-30 49 views
2

我正在構建一個使用AAD進行安全保護的.NET核心Web API,該API使用ADAL使用代表流來調用下游API。與此類似Azure的樣品:推薦用於Web API的ADAL令牌緩存?

https://github.com/Azure-Samples/active-directory-dotnet-webapi-onbehalfof

哪些是應當在這樣的場景中使用該令牌緩存的最佳做法是什麼?

  • 默認緩存是否可以接受?

  • 您是否曾經沒有緩存?

    AuthenticationContext authContext =新 AuthenticationContext(權威,NULL)

  • 如果你要建立自己的 那麼有沒有一個很好用的參考實現?

回答

4

您使用的正確的令牌緩存非常主觀,並且實際上取決於您的架構,性能要求等。

ADAL使用的默認緩存是內存中緩存,這意味着它可能不會在您的API接收的請求之間持續存在。此外,ADAL.NET使用的默認緩存是靜態類,這意味着對您的API的兩個不同請求可能會選取相同的緩存對象,這通常是意料之外的,因爲這兩個請求可能針對不同的用戶。因此,通常不推薦使用默認的ADAL緩存 - 這取決於您的Web服務器的工作方式。

相反,我們建議將null作爲令牌緩存,如果您可以管理性能命中,或者最好實現您自己的令牌緩存。

如果您想要實現自己的緩存,它將保存您的應用程序不必在每個傳入請求上向AAD發送HTTP請求(通過ADAL)。使用.NET實體框架樣本ADAL緩存實現可here,以下複製以及:

using Microsoft.IdentityModel.Clients.ActiveDirectory; 
using System; 
using System.Collections.Generic; 
using System.ComponentModel.DataAnnotations; 
using System.Data.Entity; 
using System.Linq; 
using System.Web; 

namespace TodoListWebApp.DAL 
{ 

    public class PerWebUserCache 
    { 
     [Key] 
     public int EntryId { get; set; } 
     public string webUserUniqueId { get; set; } 
     public byte[] cacheBits { get; set; } 
     public DateTime LastWrite { get; set; } 
    } 

    public class EFADALTokenCache: TokenCache 
    { 
     private TodoListWebAppContext db = new TodoListWebAppContext(); 
     string User; 
     PerWebUserCache Cache; 

     // constructor 
     public EFADALTokenCache(string user) 
     { 
      // associate the cache to the current user of the web app 
      User = user; 

      this.AfterAccess = AfterAccessNotification; 
      this.BeforeAccess = BeforeAccessNotification; 
      this.BeforeWrite = BeforeWriteNotification; 

      // look up the entry in the DB 
      Cache = db.PerUserCacheList.FirstOrDefault(c => c.webUserUniqueId == User); 
      // place the entry in memory 
      this.Deserialize((Cache == null) ? null : Cache.cacheBits); 
     } 

     // clean up the DB 
     public override void Clear() 
     { 
      base.Clear(); 
      foreach (var cacheEntry in db.PerUserCacheList) 
       db.PerUserCacheList.Remove(cacheEntry); 
      db.SaveChanges(); 
     } 

     // Notification raised before ADAL accesses the cache. 
     // This is your chance to update the in-memory copy from the DB, if the in-memory version is stale 
     void BeforeAccessNotification(TokenCacheNotificationArgs args) 
     { 
      if (Cache == null) 
      { 
       // first time access 
       Cache = db.PerUserCacheList.FirstOrDefault(c => c.webUserUniqueId == User); 
      } 
      else 
      { // retrieve last write from the DB 
       var status = from e in db.PerUserCacheList 
          where (e.webUserUniqueId == User) 
          select new 
          { 
           LastWrite = e.LastWrite 
          }; 
       // if the in-memory copy is older than the persistent copy 
       if (status.First().LastWrite > Cache.LastWrite) 
       //// read from from storage, update in-memory copy 
       { 
        Cache = db.PerUserCacheList.FirstOrDefault(c => c.webUserUniqueId == User); 
       } 
      } 
      this.Deserialize((Cache == null) ? null : Cache.cacheBits); 
     } 
     // Notification raised after ADAL accessed the cache. 
     // If the HasStateChanged flag is set, ADAL changed the content of the cache 
     void AfterAccessNotification(TokenCacheNotificationArgs args) 
     { 
      // if state changed 
      if (this.HasStateChanged) 
      { 
       Cache = new PerWebUserCache 
       { 
        webUserUniqueId = User, 
        cacheBits = this.Serialize(), 
        LastWrite = DateTime.Now 
       }; 
       //// update the DB and the lastwrite     
       db.Entry(Cache).State = Cache.EntryId == 0 ? EntityState.Added : EntityState.Modified;     
       db.SaveChanges(); 
       this.HasStateChanged = false; 
      } 
     } 
     void BeforeWriteNotification(TokenCacheNotificationArgs args) 
     { 
      // if you want to ensure that no concurrent write take place, use this notification to place a lock on the entry 
     } 
    } 

} 
+0

只是偶然在此,不是它必要的,你標誌着Clear()方法緩存= null,否則價值永遠不會從變量中移除,然後在BeforeAccess方法中,第一個if不應該被傳遞。因此您也可以獲取錯誤憑證的標記。 –