2017-02-16 29 views
0

Iは、内蔵の「設定のAzure AD認証」機能を使用して、私のMVCのWebアプリケーションを構成し、それが次のコードを提供してくれまし: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 :

まず、すべてのトークンキャッシュは、接続された機能によって自動構成されたローカルデータベースに格納されていました"defaultconnection"と呼ばれるデータベース。しかし、私は私のWebアプリケーションを公開しようとしていたときにエラーが発生し、すべてのトークンがローカルに格納されていたためです。だから、私はAzureデータベースにDBContextを移行しようとしました。私が移行した後、私はこの例外を受け続けます。これを修正する方法はありますか?

+0

Azure側のデータベースは同じに見えますか? – juunas

答えて

0

AcquireTokenSilentAsyncメソッドを呼び出す前に、リフレッシュトークンを使用せずにトークンを取得する必要があります。

たとえば、ユーザーがサインインするときに、ウェブアプリケーションがの認証コードを取得した後でトークンを取得できます。

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); 
      } 
     } 
    }); 

そして、あなたはAcquireTokenSilentAsync機能を使用するには、このシナリオのための完全なコードサンプルhereを参照することができます:ここではあなたの参照のためのコードの一部です。

関連する問題