2017-01-23 53 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'对象不为空。 –

相关问题