【问题标题】:"AADSTS50027: Invalid JWT token. Token format not valid" error in on-behalf-of scenario“AADSTS50027:无效的 JWT 令牌。令牌格式无效”代表场景中的错误
【发布时间】:2018-08-20 02:53:49
【问题描述】:

尝试使用 AcquireTokenAsync 代表 AAD 用户获取 本机 应用程序的令牌时出现上述 ADAL 错误。

场景: Angular 单页应用程序正在使用 adal.js 库为用户获取访问令牌。 此令牌被传递到本质上是相同应用程序的自托管 Web api(通过 adal.js 进行的初始登录和自托管 Web api 都使用相同的 Azure App Id)。 webapi 尝试代表用户获取一个新令牌,以使用 AcquireTokenAsync 调用另一个 Azure 托管的 web api。

代码:

var bootstrapContext =
     ClaimsPrincipal.Current.Identities.First().BootstrapContext as
          System.IdentityModel.Tokens.BootstrapContext;
var userName = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn) != null ? ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn).Value : ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email).Value;
var userAccessToken = bootstrapContext.Token;
var userAssertion = new UserAssertion(userAccessToken, "urn:ietf:params:oauth:grant-type:jwt-bearer", userName);
var authority = string.Format(System.Globalization.CultureInfo.InvariantCulture, _aadInstance, _tenant);

var authContext = new AuthenticationContext(authority, new TokenCache());

var result = await authContext.AcquireTokenAsync(_resourceUri, _appId, userAssertion);
var accessToken = result.AccessToken;
return accessToken;

请注意,Azure 中的应用注册是没有应用密钥的本机应用。如果我将应用程序创建为 webapi 应用程序并在 ClientCredential 对象中使用 appid 和密钥,则会按预期返回令牌。

var clientCredential = new ClientCredential(_appId, _appKey);
...
var result = await authContext.AcquireTokenAsync(_resourceUri, clientCredential, userAssertion);

我无法让它与本机应用程序一起使用。有什么建议?或者任何想法为什么我会收到无效令牌错误?

理由: 我需要使用本机应用程序而不是 webapi 应用程序注册的原因是,客户端(角度 SPA 应用程序 + 自托管 webapi)部署在现场而不是 Web 服务器上。我不想使用应用程序密钥部署应用程序,因为应用程序密钥过期并且在过期时使用新密钥重新部署客户端应用程序不是一个好的选择。使用没有密钥的本机应用程序将避免这样做。

谢谢。

【问题讨论】:

  • 是否可以绕过第一个 API 的 AcquireTokenAsync 调用来获取新的令牌来调用第二个 API? IE。在从 adal.js 首次登录时,用户被授予调用下游 API 的令牌?

标签: oauth-2.0 asp.net-web-api2 jwt access-token adal


【解决方案1】:

当使用代表授权类型调用令牌端点时,documentation 似乎建议您需要一个机密客户端,因为client_secret 参数已根据需要记录在案。这意味着您不能将该授权类型与本机(公共)客户端类型一起使用。

但是,如果您从自托管 Web API 进行调用并且它是一个机密客户端,那么 on-behalf-of 应该可以工作。

是否可以绕过第一个 API 的 AcquireTokenAsync 调用 获取一个新的令牌来调用第二个 API? IE。在初次登录时 从 adal.js 中,用户被授予调用下游 API 的令牌?

是的,我认为您可以通过 manifest configuration 进行此操作。如果您修改您的 AAD 应用程序权限并根据需要在您的相关应用程序之间添加委派权限 (requiredResourceAccess)。初始令牌请求需要针对下游 Web API 的资源 ID,并且此资源 ID 将在每个资源中验证为 audience

另外,我相信您可以在 Web API 的清单中设置 KnownClientApplications 以包含您的 Angular 应用注册的应用 ID,这样一旦用户同意您的本机应用同意,将自动为 Web API 创建同意,而无需明确同意每个 API。

虽然这真的不是一个好的解决方案!

另外,正如您所说,您遇到的错误与 JWT 令牌格式无效有关,原始访问令牌是否肯定以 BootstrapContext 的形式传递?

在owin中间件中,我似乎记得访问令牌默认情况下不会传递给声明主体,您必须设置

SaveSignInToken = true

作为中间件中TokenValidationParameters 的一部分。

例如

 app.UseWindowsAzureActiveDirectoryBearerAuthentication(
                new WindowsAzureActiveDirectoryBearerAuthenticationOptions
                {
                    Tenant = ConfigurationManager.AppSettings["ida:Tenant"],


TokenValidationParameters = new TokenValidationParameters{ SaveSigninToken = true, ValidAudience= ConfigurationManager.AppSettings["ida:Audience"] }
                });

代码示例here

【讨论】:

  • 肯定会保存令牌并将其传递给 AcquireTokenAsync 调用。实际上,将此令牌与非本地应用令牌进行比较,除了应用 ID 之外,它们是相同的。我会尝试按照您的建议修改应用清单并报告。
  • 将 Angular(本机)appId 添加到下游 API 清单中的“knownClientApplications”列表中,似乎无法解决它。我仍然只在 JWT 令牌的“aud”中看到本机 appId。有什么想法我可能做错了吗?
  • 似乎一个令牌与一个resourceid(观众)相关,因此仅当两个 Web API 在不记名令牌中检查相同的 audience 时才使用相同的令牌。原始令牌请求需要针对链中第二个 Web API 的 resourceid - SPA 和其他 Web API 应该允许这个 audience,因为它是他们的 requiredResourceAccess。虽然这看起来很可怕!我认为您对on-behalf-of flow 的想法更好,应该可行。
  • 我假设您的 SPA 应用正在使用 implicit 流程 - 此文档可能会有所帮助:github.com/Azure-Samples/… 祝您好运!
  • 我需要先确认我正在做的事情是有效的和可能的,如果是的话,那么同意我更愿意深入了解“无效令牌”错误。是的,SPA 应用正在使用隐式流程。
【解决方案2】:

如果我完全删除客户端应用程序 ID,我可以让它工作,但我不确定这是正确的解决方案。所以,如果adal.js获取到的初始token是给下游API的,而自托管的web api Audience也是下游API的app Id,它只是将JWT token直接传给下游API,并没有得到一个新的令牌。这很有效,并且达到了在客户端不存储任何应用程序密钥的预期结果,但感觉不对,感觉像是在欺骗。

【讨论】:

    【解决方案3】:

    找到此内容的 Google 搜索的通用解决方案。

    您可能需要在查询中使用 ClientCredential 类而不是 ClientAssertion 类 - 或反过来获得 AcquireToken 的正确重载

    这个问题的真正答案(非常有帮助和深思熟虑)可以帮助您解决这个问题。

    【讨论】:

      猜你喜欢
      • 2021-04-12
      • 2022-07-08
      • 2021-04-13
      • 2019-03-19
      • 1970-01-01
      • 2021-09-25
      • 2016-09-22
      • 2018-07-14
      • 2020-04-19
      相关资源
      最近更新 更多