AAD API 访问委托权限如何工作?

How does AAD API Access delegate permission work?

我在了解 API 访问委托权限如何与 azure 活动目录一起工作时遇到了一些麻烦。我觉得我可能误解了 AAD 工作原理的一个关键方面。

这是我的设置

  1. 我有一个 Web 应用程序,我们称它为 WebApp。我创造了 Web 应用程序的 AAD 并使用 AAD App ID 注册。让我们 将其命名为 App ID A
  2. 我有一个 Web Api 我们称它为 Api 服务。我还为它创建了一个 AAD 并注册了一个 AAD App ID。全部吧 App ID B.
  3. 在 AAD App ID A 中,我更新了点击 API 访问 -> 所需权限 -> 添加(App ID B ; Web API)权限
  4. 我已更新 AAD App ID B 中的清单,同意 knownClientApplications 以包含 Web 应用程序的客户端 ID
  5. 我还为两个应用程序启用了 oauth2AllowImplicitFlow 清单。

我想做的是,用户登录网络应用程序标志。当它登录时,用户能够获取特定 Web App App ID A 的令牌。用户应该能够使用该令牌并使用 App ID B 访问 Api 服务。我想通过配置整个 API 访问 -> Web 应用程序中的必需权限,它会给我授权登录用户与 Api Service WebApi 通信的权限。

当我检查 JWT 令牌时,我注意到有对 Microsoft Graph 的声明,但没有对 Api 服务的声明。我不应该看到索赔吗?

当我尝试使用令牌时,它出现 404 身份验证错误。

任何建议表示赞赏, 谢谢, 德里克

更新

回应@joonasw

其实我开始的时候看了你写的例子。

https://joonasw.net/view/aspnet-core-2-azure-ad-authentication

在示例中,Web 应用程序初始化为:

.AddOpenIdConnect(opts =>
        {
        Configuration.GetSection("OpenIdConnect").Bind(opts);
            opts.Events = new OpenIdConnectEvents
        {
            OnAuthorizationCodeReceived = ctx =>
            {
                return Task.CompletedTask;
            }
        };
        });

在 HomeController 中,有代码可以检索图形的令牌 api

private async Task<string> GetAccessTokenAsync()
{
    string authority = _authOptions.Authority;

    string userId = User.FindFirstValue("http://schemas.microsoft.com/identity/claims/objectidentifier");
    var cache = new AdalDistributedTokenCache(_cache, _dataProtectionProvider, userId);

    var authContext = new AuthenticationContext(authority, cache);

    //App's credentials may be needed if access tokens need to be refreshed with a refresh token
    string clientId = _authOptions.ClientId;
    string clientSecret = _authOptions.ClientSecret;
    var credential = new ClientCredential(clientId, clientSecret);

    var result = await authContext.AcquireTokenSilentAsync(
        "https://graph.microsoft.com",
        credential,
        new UserIdentifier(userId, UserIdentifierType.UniqueId));

    return result.AccessToken;
}

根据我的理解,当用户最初登录到 Web 应用程序时,它将触发 OnAuthorizationCodeReceived() 方法,它将使用 Web 应用程序的 clientId/clientSecret/resource。令牌存储在密钥 resource/client id 下的分布式令牌缓存中。

在示例中,GetAccessTokenAsync() 用于获取访问图的令牌API。

就我而言,我希望更新该方法以检索具有不同 clientId/clientSecret/resoruce 的 WebApi 的令牌。在我的例子中,AcquireTokenSilentAsync 将抛出 AdalTokenAcquisitionExceptionFilter,因为所需的令牌未存储在缓存中,而在 AdalTokenAcquisitionExceptionFilter 中它将调用尝试重新验证

context.Result = new ChallengeResult();

这将重定向到身份验证页面,然后点击 AddOpenIdConnect() 方法。但是,openIdConnect 配置有 Web 应用程序 clientID/ClientSecret/Resource,并且不会正确存储新令牌。它将尝试再次调用 GetAccessTokenAsync(),整个过程将陷入无限循环。

在示例中,如果您要注释掉 app.settings 中的 "Anthentication:resource",您将遇到与无限循环相同的问题。发生的情况是您最初在没有指定资源的情况下正确地进行了身份验证。然后,当您单击尝试获取新资源 Microsoft Graph 的令牌时,它无法在缓存中找到它,然后一遍又一遍地尝试重新验证。

我还注意到 acquireAsyncAuthentication 仅 returns 具有不记名令牌类型的 AuthenticationResult。在这种情况下,您将如何获得刷新令牌?

有什么建议吗? 谢谢, 德里克

更新(解决方案)

感谢@jaanus。您所要做的就是将资源更新为 Web api 的 clientid,并将其传递到 AcquireTokenSilentAsync。您可以从 Azure 门户获取的 Web api id uri 无效。

好的,看来这里有多个问题。我会试着让你明白这些东西。

将 "Web App" 的客户端 ID 添加到 "ApiService" knownClientApplications 是个好主意。 它允许同时对两个应用程序进行同意。不过,这实际上只对 multi-tenant 场景很重要。

现在,您的 Web 应用程序将在某个时候获取访问令牌。 当它这样做时,它必须指定一个 resource 参数。 此参数告诉 AAD 您希望调用哪个 API。 对于 "ApiService",您应该使用其客户端 ID 或应用程序 ID URI(这更常见)。

根据您的 Web 应用程序的类型,获取访问令牌的方式略有不同。 对于 "traditional" back-end 应用程序,通常使用授权码授予流程。 在此流程中,您的 back-end 在用户登录后获得授权代码,然后您的 Web 应用程序可以将该代码交换为访问令牌。

对于 front-end JavaScript 应用程序,您将使用您已允许的隐式授权流程(顺便说一下,无需在 API 中启用它). 这允许您直接从授权端点 (/oauth2/authorize) 获取访问令牌,而无需像通常那样与令牌端点通信。 如果您愿意,您实际上可以在 URL 的片段中登录后立即获得访问令牌。 ADAL.JS 如果您要走这条路,这对您来说会容易很多。

您收到身份验证错误的原因是因为访问令牌可能适用于 Microsoft Graph API。您需要为 API 请求访问令牌。 访问令牌始终仅对一个 API.

有效