2017-02-16 73 views
0

我配置我的MVC Web應用程序使用內置的「配置Azure的AD身份驗證」功能,並將其與下面的代碼提供給我:Microsoft.IdentityModel.Clients.ActiveDirectory.AdalSilentTokenAcquisitionException:無法靜默獲取令牌。調用方法AcquireToken

public async Task<string> GetTokenForApplication() 
    { 
     string signedInUserID = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value; 
     string tenantID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value; 
     string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value; 

     // 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 database 
     AuthenticationContext authenticationContext = new AuthenticationContext(aadInstance + tenantID, new ADALTokenCache(signedInUserID)); 
     AuthenticationResult authenticationResult = await authenticationContext.AcquireTokenSilentAsync(graphResourceID, clientcred, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId)); 
     return authenticationResult.AccessToken; 
    } 

而且繼承人的模型

public class ADALTokenCache : TokenCache 
{ 
    private ApplicationDbContext db = new ApplicationDbContext(); 
    private string userId; 
    private UserTokenCache Cache; 

    public ADALTokenCache(string signedInUserId) 
    { 
     // associate the cache to the current user of the web app 
     userId = signedInUserId; 
     this.AfterAccess = AfterAccessNotification; 
     this.BeforeAccess = BeforeAccessNotification; 
     this.BeforeWrite = BeforeWriteNotification; 
     // look up the entry in the database 
     Cache = db.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == userId); 
     // place the entry in memory 
     this.Deserialize((Cache == null) ? null : MachineKey.Unprotect(Cache.cacheBits,"ADALCache")); 
    } 

    // clean up the database 
    public override void Clear() 
    { 
     base.Clear(); 
     var cacheEntry = db.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == userId); 
     db.UserTokenCacheList.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.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == userId); 
     } 
     else 
     { 
      // retrieve last write from the DB 
      var status = from e in db.UserTokenCacheList 
         where (e.webUserUniqueId == userId) 
      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.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == userId); 
      } 
     } 
     this.Deserialize((Cache == null) ? null : MachineKey.Unprotect(Cache.cacheBits, "ADALCache")); 
    } 

    // 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 UserTokenCache 
      { 
       webUserUniqueId = userId, 
       cacheBits = MachineKey.Protect(this.Serialize(), "ADALCache"), 
       LastWrite = DateTime.Now 
      }; 
      // update the DB and the lastwrite 
      db.Entry(Cache).State = Cache.UserTokenCacheId == 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 
    } 

    public override void DeleteItem(TokenCacheItem item) 
    { 
     base.DeleteItem(item); 
    } 
} 

的DbContext :

public class ApplicationDbContext : DbContext 
{ 
    public ApplicationDbContext() 
     : base("AzureDatabase") 
    { 
    } 

    public DbSet<UserTokenCache> UserTokenCacheList { get; set; } 
} 

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

起初,所有的令牌緩存都存儲在本地數據庫自動配置的功能連接到一個名爲「defaultconnection」的數據庫。然而,當我試圖發佈我的網絡應用程序時,我得到了錯誤,我意識到這是因爲所有的令牌都存儲在本地。所以我嘗試將DBContext遷移到我的Azure數據庫。遷移後,我不斷收到此異常。有沒有辦法來解決這個問題??

+0

Azure側的數據庫看起來是否完全相同? – juunas

回答

0

根據我的理解,在我們調用AcquireTokenSilentAsync方法之前,我們應該在不使用刷新令牌的情況下執行獲取令牌。

例如,當用戶登錄時,web應用得到授權碼後,我們可以獲取令牌。這是給你參考的一段代碼:

app.UseOpenIdConnectAuthentication(
    new OpenIdConnectAuthenticationOptions 
    { 
     ClientId = SettingsHelper.ClientId, 
     Authority = SettingsHelper.Authority,     

     Notifications = new OpenIdConnectAuthenticationNotifications() 
     { 
      // 
      // If there is a code in the OpenID Connect response, redeem it for an access token and refresh token, and store those away. 

      AuthorizationCodeReceived = (context) => 
      { 
       var code = context.Code; 

       ClientCredential credential = new ClientCredential(SettingsHelper.ClientId, SettingsHelper.ClientSecret); 
       String UserObjectId = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value; 

       AuthenticationContext authContext = new AuthenticationContext(SettingsHelper.Authority, new ADALTokenCache(UserObjectId)); 

       authContext.AcquireTokenByAuthorizationCode(code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, SettingsHelper.AADGraphResourceId); 
       //authContext.TokenCache.Clear(); 
       return Task.FromResult(0); 
      } 
     } 
    }); 

而且您可以參閱完整的代碼示例here此方案中使用AcquireTokenSilentAsync功能。

相關問題