尝试使用 AcquireTokenAsync 代表 AAD 用户获取本机应用的令牌时出现上述 ADAL 错误。
场景: Angular 单页应用程序正在使用 adal.js 库来获取用户的访问令牌。 此令牌将传递到自承载 Web API,该 API 本质上是相同的应用程序(通过 adal 进行的初始登录.js和自承载 Web API 使用相同的 Azure 应用 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 应用,并在客户端凭据对象中使用 appid 和密钥,则会按预期返回令牌。
var clientCredential = new ClientCredential(_appId, _appKey);
...
var result = await authContext.AcquireTokenAsync(_resourceUri, clientCredential, userAssertion);
我无法让它与本机应用程序一起使用。 有什么建议吗? 或者为什么我收到无效令牌错误的任何想法?
理由: 我需要使用本机应用程序而不是 webapi 应用程序注册的原因是,客户端(angluar SPA 应用程序 + 自托管 webapi)部署在现场而不是 Web 服务器上。 我不想使用应用密钥部署应用,因为应用密钥会过期,并且在客户端应用过期时使用新密钥重新部署客户端应用不是一个好选择。 使用没有密钥的本机应用程序将避免这样做。
谢谢。
使用代表授权类型调用令牌终结点时,文档似乎建议你需要有一个机密客户端,因为client_secret
参数是必需的。这意味着不能将该授权类型与本机(公共)客户端类型一起使用。
但是,如果从自承载 Web API 进行调用,并且它是机密客户端,则on-behalf-of
应该可以正常工作。
是否可以绕过第一个API的AcquireTokenAsync调用 获取新令牌以调用第二个 API?即在初始登录时 从 adal.js,用户被授予调用下游 API 的令牌?
是的,我认为您可以通过清单配置来做到这一点。如果修改 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"] }
});
此处的代码示例。
如果我完全删除客户端应用程序 id,我能够让它工作,但我不确定这是正确的解决方案。因此,如果 adal 检索的初始令牌.js 用于下游 API,并且自托管 Web API 受众也是下游 API 应用 ID,并且它只是将 JWT 令牌直接传递给下游 API,并且不会获取新令牌。这有效,并实现了不在客户端上存储任何应用密钥的预期结果,但感觉不对,感觉像欺骗。
找到这个的谷歌搜索的通用解决方案。
在查询中,您可能需要 ClientCredential 类而不是ClientAssertion类 - 或者相反,以获得 AcquireToken 的正确重载
这个问题的真正答案(非常有帮助和周到)可以帮助您解决这个问题。