AcquireTokenSilent无法以静默方式获取令牌?

时间:2017-02-25 21:09:50

标签: c# asp.net azure token adal

我在Azure上有一个托管应用程序。在SiteMaster页面(母版页)中,我试图获取所有用户的AD组,因为我的应用程序是基于角色的应用程序,其中每个用户都属于Azure组,每个组都可以执行某些功能。

页面加载事件中的代码如下所示:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div>
  <div class="div1">
    <ul>
      <li>Line 1</li>
    </ul>
    <ul>
      <li>Line 1</li>
      <li>Line 2</li>
    </ul>
    <ul>
      <li>Line 1</li>
      <li>Line 2</li>
      <li>Line 3</li>
    </ul>
  </div>      
</div>

请注意,我正在调用实际带来用户所属的所有组的函数'GetUserData()'。该函数的代码如下:

private static string clientId = ConfigurationManager.AppSettings["ida:ClientID"];
private static string appKey = ConfigurationManager.AppSettings["ida:ClientSecret"];
private static string aadInstance = ConfigurationManager.AppSettings["ida:AADInstance"];
private static string graphResourceId = "https://graph.windows.net";

protected void Page_Load(object sender, EventArgs e)
{
      if (Request.IsAuthenticated)
      {
          IList<string> groups = GetUserData();
      }
}

'GetUserData()'函数正在调用另一个名为'GetTokenForApplication()'的函数,该函数负责获取Azure的令牌表单。上一个函数的源代码如下:

        public IList<string> GetUserData()
        {
            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;

            Uri servicePointUri = new Uri(graphResourceId);
            Uri serviceRoot = new Uri(servicePointUri, tenantID);
            ActiveDirectoryClient activeDirectoryClient = new ActiveDirectoryClient(serviceRoot,
                    async () => await GetTokenForApplication());

            IList<string> groupMembership = new List<string>();
            // use the token for querying the graph to get the user details
            IUser user = activeDirectoryClient.Users
                .Where(u => u.ObjectId.Equals(userObjectID))
                .ExecuteAsync().Result.CurrentPage.ToList().First();
            var userFetcher = (IUserFetcher)user;
            requestor = user.DisplayName;
            IPagedCollection<IDirectoryObject> pagedCollection = userFetcher.MemberOf.ExecuteAsync().Result;
            do
            {
                List<IDirectoryObject> directoryObjects = pagedCollection.CurrentPage.ToList();
                foreach (IDirectoryObject directoryObject in directoryObjects)
                {
                    if (directoryObject is Group)
                    {
                        var group = directoryObject as Group;
                        groupMembership.Add(group.DisplayName);
                    }
                }
                pagedCollection = pagedCollection.GetNextPageAsync().Result;
            } while (pagedCollection != null);

            return groupMembership;
        }

我的问题有时是当用户尝试登录我的应用程序时他/她得到错误 protected 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 EF DB AuthenticationContext authenticationContext = new AuthenticationContext(aadInstance + tenantID, new ADALTokenCache(signedInUserID)); AuthenticationResult authenticationResult = await authenticationContext.AcquireTokenSilentAsync(graphResourceId, clientcred, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId)); return authenticationResult.AccessToken; }

在某些我不知道的情况下会发生此错误,当它发生时,它不会影响所有用户。有些用户仍然可以进入而不会出现此错误。任何关于为什么会发生这种情况的建议或想法,以及如何解决这样的错误?

这是我的Stack Trace:

Failed to acquire token silently. Call method AcquireToken

谢谢!

2 个答案:

答案 0 :(得分:1)

AcquireTokenSilentAsync会尝试各种方式来获取有效的令牌,而不会提示您进行交互式身份验证请求。如果它不能(通过缓存或刷新令牌),那么它将生成异常。

您可以抓住this exception并决定提示进行交互式身份验证或无提示失败,并要求最终用户稍后登录,具体取决于您的应用逻辑。 Here是此互动调用的参考文档。

            AuthenticationResult result;
            try
            {
                 result = await authContext.AcquireTokenSilentAsync(resourceId, clientId);
            }
            catch (AdalException ex)
            {
                if (ex.ErrorCode == "failed_to_acquire_token_silently")
                {
                    // There are no tokens in the cache. 
                    result = await authContext.AcquireTokenAsync(resourceId, clientId, redirectUri, new PlatformParameters(PromptBehavior.Always));

                }
                else
                {
                    // An unexpected error occurred.
                    string message = ex.Message;
                    if (ex.InnerException != null)
                    {
                        message += "Inner Exception : " + ex.InnerException.Message;
                    }
                    MessageBox.Show(message);
                }

Here是一个很棒的代码示例.NET MVC应用程序,它向您展示如何使用ADAL。

答案 1 :(得分:0)

AFAIK,当您尝试以静默方式获取令牌(调用AcquireTokenSilentAsync以获取accessToken)时,它将从TokenCache获取令牌或静默使用refreshToken。如果访问令牌和刷新令牌已过期,您可能会收到AdalSilentTokenAcquisitionException。您必须捕获AdalSilentTokenAcquisitionException异常:

try
{
    AuthenticationContext authenticationContext = new AuthenticationContext(aadInstance + tenantID, new ADALTokenCache(signedInUserID));
    AuthenticationResult authenticationResult = await authenticationContext.AcquireTokenSilentAsync(graphResourceId, clientcred, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));
    return authenticationResult.AccessToken;
}
catch (AdalSilentTokenAcquisitionException)
{
    //told or force the user to reauthentificate.

    return null;
}

在异常句柄中,您可以告诉用户重新验证或直接执行OAuth身份验证过程。