2017-01-23 60 views
0

圖形API的訪問令牌張貼在StackOverflow的問題是如下無法讀取存儲在ADAL TokenCache從的WebAPI

我們有一個多租戶的Web應用程序(ASP.NET MVC 5.2.2),這是受Azure AD保護以進行用戶身份驗證,Web應用程序調用後端Rest API(ASP.NET Web API 5.2.3),該API也受到威盛OAuth 2.0持票人令牌的保護。我們使用Open-ID Connect OWIN模塊在Web應用程序中使用Open-ID Connect協議。

我們需要使用Graph API版本1.5將租戶的Azure AD目錄用戶和組導入應用商店。我們使用Microsoft ADAL 2.0獲取訪問令牌和刷新令牌,並將它們存儲在ADAL令牌緩存中擴展到Redis緩存。

設計是這樣一種方式,Web應用程序將用戶上下文傳遞給Web API,其中包括SignInUserId,ObjectId,TenantId和Web Api使用此上下文以及Web App標識來讀取已存儲在TokenCache中的訪問令牌(如果過期刷新訪問令牌)並使用此令牌獲取租戶AD數據。

  // get a token for the Graph without triggering any user interaction (from the cache, via multi-resource refresh token, etc) 
      ClientCredential clientcred = new ClientCredential(clientId, appKey); 
      // initialize AuthenticationContext with the token cache of the currently signed in user, as kept in the app's EF DB 
      AuthenticationContext authContext = new AuthenticationContext(string.Format("https://login.microsoftonline.com/{0}", tenantID), new CustomTokenCache(signedInUserID)); 
      AuthenticationResult result = await authContext.AcquireTokenSilentAsync(graphResourceID, clientcred, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId)); 
      return result.AccessToken; 

當讀取即使令牌從緩存中直接訪問FailedToRefreshAccessToken拋出異常的令牌。

任何幫助,將不勝感激。

Design

Exception details

代碼定製令牌緩存

public class PerUserCache 
    { 
     public string userUniqueId { get; set; } 
     public byte[] cacheBits { get; set; } 
     public DateTime LastWrite { get; set; } 

    } 

    public class CustomTokenCache : TokenCache 
    { 

     string userID; 
     PerUserCache Cache; 
     ICache database = CacheFactory.GetCacheInstance(); 

    /// <summary> 
    /// 
    /// </summary> 
    /// <param name="userID"></param> 
     public CustomTokenCache(string userID) 
     { 
      // associate the cache to the web api 
      this.userID = userID; 

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

      // look up the entry in the DB 

       Cache = database.Get<PerUserCache>(this.userID); 

      // place the entry in memory 
      this.Deserialize((Cache == null) ? null : Cache.cacheBits); 
     } 

     // clean up the DB 
     public override void Clear() 
     { 
      base.Clear(); 
     } 
    enter code here 
     // 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 = database.Get<PerUserCache>(userID); 
      }`enter code here` 
      else 
      { // retrieve last write from the DB 
       var status = database.Get<PerUserCache>(userID).LastWrite; 
       // if the in-memory copy is older than the persistent copy 
       if (status > Cache.LastWrite) 
       //// read from from storage, update in-memory copy 
       { 
        Cache = database.Get<PerUserCache>(userID); 
       } 
      } 
      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 PerUserCache 
       { 
        userUniqueId = userID, 
        cacheBits = this.Serialize(), 
        LastWrite = DateTime.Now 
       }; 
       //// update the DB and the lastwrite     
       database.Set<PerUserCache>(userID, Cache,null); 
       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

您能否獲得有關'FailedToRefreshAccessToken'異常的詳細異常消息?分享「CustomTokenCache」類的代碼也很有幫助。 –

+0

Hi @Fei Xue,編輯文章 – madhu

回答

0

似乎有關於CustomTokenCache代碼沒有問題。通常,這個問題是由於無法找到特定用戶的緩存而導致的。

您可以通過將斷點設置爲BeforeAccessNotification的方法來驗證此問題,並確保Cache對象在反序列化時不爲空。

此外,您可以直接基於userObjectID檢查Redis中的緩存。

此外,由於您指出您的Web應用程序將令牌存儲在上圖中的緩存存儲中。你介意在你的web應用程序中分享如何獲取令牌的代碼嗎?

+0

Hi Fei xue,我們已經檢查了CustomTokenCache類,我們能夠獲得deserailized緩存對象。我們能夠從Web應用中獲取標記,當我們嘗試從Web APi拋出異常 – madhu

+0

請確保您基於相同的用戶對象ID從緩存中獲取令牌。並且我還建議調試web API以確保在** web API **項目中反序列化時'Cache'對象不爲空。 –

相關問題