【问题标题】:ADAL - AcquireTokenSilentAsync fails (Azure Active Directory Authentication Libraries)ADAL - AcquireTokenSilentAsync 失败(Azure Active Directory 身份验证库)
【发布时间】:2016-09-09 12:30:54
【问题描述】:

我编写了一个新的应用程序来通过 REST API 访问办公室数据,因此我想使用新的 认证模型(V2.0 Endpoint)

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,但此信息未存储在 Token 对象中。 Token 的 UserInfo 始终为空。因为该字段为null,所以Token缓存找不到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

【问题讨论】:

    标签: c# azure oauth-2.0 office365 adal


    【解决方案1】:

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

    目前库有一个bug,因为它还在检查,如果为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;
    }
    

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

    【讨论】:

    • 目前我已经使用了这个解决方法,但是这样ADAL库的内置Token缓存就不能用了
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多