ADAL - AcquireTokenSilentAsync失败(Azure活动目录身份验证库)

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

V2.0端点有何不同

我可以通过调用来获取令牌

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

返回结果:

返回的令牌包含唯一标识符,但此信息未存储在令牌对象中。令牌的用户信息始终为null。由于此字段为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"
}

类似的问题: 在这里
1个回答

3

微软已经移除了profile_info,您可以在这里阅读到更多信息:ADV2的重要更新

目前,该库存在一个bug,因为它仍然检查它,如果为空,它将不返回用户信息。

正确的信息在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 入门 如我所说,所有信息都存储在 token_id 中,在上面的链接中,您可以阅读到:
引入版的 ADAL v4 不直接返回 ID 令牌,但可以访问。此处包含的方法旨在解决此问题,直到 ADAL 得到更新。
他们解释了一种访问 Token 的方法:
  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;
}

我还没有测试过这个,但是当我测试过后我会更新这篇文章,或者如果有人更快的话,请留下评论 :-)


1
目前,我已经使用这种解决方法,但是这样就无法使用ADAL库的内置Token缓存。 - Manuel Amstutz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接