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

标签 c# azure oauth-2.0 office365 adal

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

What's different about the v2.0 endpoit

我可以通过调用来获取 token

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("co<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="204e544f534f60464f4f0e4348" rel="noreferrer noopener nofollow">[email protected]</a>", UserIdentifierType.RequiredDisplayableId))
    }

返回的 token 确实包含UniqueId,但此信息未存储在Token对象中。 Token的UserInfo始终为空。由于该字段为空,所以Token缓存找不到该Token。

感谢您的提示和想法

enter image description here

返回 token

   {  
   "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

最佳答案

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

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

正确的信息位于 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 中,在上面的链接中您可以阅读:

The prerelease version of ADAL v4 doesn't return the ID token directly, but it is accessible. The method included here is intended to work around this issue until ADAL is updated.

他们解释了访问 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;
}

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

关于c# - ADAL - AcquireTokenSilentAsync 失败(Azure Active Directory 身份验证库),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37207813/

相关文章:

c# - 以编程方式在 Excel 中插入单元格注释

sql-server - 如何监控 Azure SQL 数据库硬件

Azure 应用服务访问文件存储以使用 webjob 复制内容

azure - 在身份验证期间将 "RequireMFA"信息从 Azure SSO 转发到 OnPrem ADFS

node.js - 如何从 OAuth2 Google API 获取电子邮件和个人资料信息?

ruby-on-rails - ruby 的 oauth2 grant_type

oauth-2.0 - 使用 OAuth2 将 JHipster 中的前端和 API 服务器分开不起作用

c# - 你会分享你的想法如何从嵌入式 Python.Net 调用 python 命令吗?

c# - 在C#中关闭表单事件

c# - 创建文本文件并使其隐藏和只读 c#