ADAL - AcquireTokenSilentAsync失败(Azure Active Directory身份验证库)

时间:2016-05-13 10:36:31

标签: c# azure oauth-2.0 office365 adal

我编写了一个新的应用程序来通过其余的API访问办公室数据,因此我想使用新的 身份验证模型(V2.0端点)

What's different about the v2.0 endpoit

我可以通过调用

获得令牌
private static string[] scopes = { "https://outlook.office.com/mail.read", "https://outlook.office.com/calendars.read" };
    public async Task<ActionResult> SignIn()
    {
     ... SNIP
      Uri authUri = await authContext.GetAuthorizationRequestUrlAsync(scopes, null, clientId, redirectUri, new UserIdentifier("contoso@foo", UserIdentifierType.RequiredDisplayableId), null);        
      return Redirect(authUri.ToString());
    }
authContext.AcquireTokenByAuthorizationCodeAsync(authCode, redirectUri, credential, scopes)

问题是对

的第二次调用
    public async Task<ActionResult> SignIn()
    {
     ... SNIP
     var authResult = authContext.AcquireTokenSilentAsync(scopes, clientId, new UserIdentifier("contoso@foo.ch", UserIdentifierType.RequiredDisplayableId))
    }

返回的令牌确实包含UniqueId,但此信息不存储在令牌对象中。令牌的UserInfo始终为null。由于此字段为空,因此令牌缓存无法找到令牌。

感谢您的提示和想法

enter image description here

返回令牌

   {  
   "aud":"https://outlook.office.com",
   "iss":"https://sts.windows.net/f2ac6f3f-3df0-4068-a677-e4dfdf924b2/",
   "iat":146   dfdf21,
   "nbf":146   dfdf4621,
   "exp":1463   dfdf38521,
   "acr":"1",
   "amr":[  
      "pwd"
   ],
   "appid":"b13dfdf9-0561-4dfdff5-945c-778dfdf0de5cd",
   "appidacr":"1",
   "family_name":"Pan",
   "given_name":"Peter",
   "ipaddr":"12.12.12.17",
   "name":"Peter Pan",
   "oid":"4b83dfdfdb-f6db-433e-b70a-2f9a6dbbeb48",
   "puid":"100dfdfdfF5FBC",
   "scp":"Calendars.Read Mail.Read Mail.ReadWrite",
   "sub":"Z-chdfdsfnWqduUkCGZpsIdp-fdhpMMqqtwcHGs",
   "tid":"f2ac6f3f-3560-4068-a677-e4bfe0c924b2",
   "unique_name":"foo@contoso",
   "upn":"foo@contoso",
   "ver":"1.0"
}

类似的问题: Here

1 个答案:

答案 0 :(得分:3)

Microsoft已删除profile_info,您可以在此处阅读: Important Updates to ADV2

目前该库有一个错误,因为它仍然检查它,如果它是null,它将不会返回用户信息。

正确的信息在token_id ...

类:TokenResponse

private AuthenticationResultEx GetResult(string token, string scope, long expiresIn)
{
  DateTimeOffset expiresOn = (DateTimeOffset) (DateTime.UtcNow + TimeSpan.FromSeconds((double) expiresIn));
  AuthenticationResult authenticationResult = new AuthenticationResult(this.TokenType, token, expiresOn);
  ProfileInfo profileInfo = ProfileInfo.Parse(this.ProfileInfoString);
  if (profileInfo != null)
  {
    string tenantId = profileInfo.TenantId;
    string str1 = (string) null;
    string str2 = (string) null;
    if (!string.IsNullOrWhiteSpace(profileInfo.Subject))
      str1 = profileInfo.Subject;
    if (!string.IsNullOrWhiteSpace(profileInfo.PreferredUsername))
      str2 = profileInfo.PreferredUsername;
    authenticationResult.UpdateTenantAndUserInfo(tenantId, this.ProfileInfoString, new UserInfo()
    {
      UniqueId = str1,
      DisplayableId = str2,
      Name = profileInfo.Name,
      Version = profileInfo.Version
    });
  }
  return new AuthenticationResultEx()
  {
    Result = authenticationResult,
    RefreshToken = this.RefreshToken,
    ScopeInResponse = AdalStringHelper.CreateArrayFromSingleString(scope)
  };
}

我希望他们能尽快解决,我也在等待: - )

修改

我在这里找到了一些有趣的东西: Dev Outlook get started

正如我已经说过的,存储在token_id中的所有信息,在上面的链接中你可以读到:

  

ADAL v4的预发布版本不会直接返回ID令牌,但可以访问它。此处包含的方法旨在解决此问题,直到更新ADAL。

他们解释了访问令牌的方法:

  private string GetUserEmail(AuthenticationContext context, string clientId)
{
    // ADAL caches the ID token in its token cache by the client ID
    foreach (TokenCacheItem item in context.TokenCache.ReadItems())
    {
        if (item.Scope.Contains(clientId))
        {
            return GetEmailFromIdToken(item.Token);
        }
    }
    return string.Empty;
}

    private string GetEmailFromIdToken(string token)
{
    // JWT is made of three parts, separated by a '.' 
    // First part is the header 
    // Second part is the token 
    // Third part is the signature 
    string[] tokenParts = token.Split('.');
    if (tokenParts.Length < 3)
    {
        // Invalid token, return empty
    }
    // Token content is in the second part, in urlsafe base64
    string encodedToken = tokenParts[1];
    // Convert from urlsafe and add padding if needed
    int leftovers = encodedToken.Length % 4;
    if (leftovers == 2)
    {
        encodedToken += "==";
    }
    else if (leftovers == 3)
    {
        encodedToken += "=";
    }
    encodedToken = encodedToken.Replace('-', '+').Replace('_', '/');
    // Decode the string
    var base64EncodedBytes = System.Convert.FromBase64String(encodedToken);
    string decodedToken = System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
    // Load the decoded JSON into a dynamic object
    dynamic jwt = Newtonsoft.Json.JsonConvert.DeserializeObject(decodedToken);
    // User's email is in the preferred_username field
    return jwt.preferred_username;
}

我还没有测试过这个,但是当我测试它时我会更新这篇文章,或者如果他更快的话,我会另外发表评论: - )