在单个 IPublicClientApplication.AcquireTokenSilent 调用中混合图形和 customAPI 范围

Mixing graphs and customAPI scopes in single IPublicClientApplication.AcquireTokenSilent call

我有一个应用程序需要访问自定义 API 以及通过图表 API 发送电子邮件的能力。 当我获得访问令牌时,我似乎只能传递图形或我的 api 范围,但不能同时传递两者。

我按如下方式创建我的应用程序

_clientApp = PublicClientApplicationBuilder.Create(ClientId)
            .WithAuthority(AzureCloudInstance.AzurePublic, Tenant)
            .Build();

然后我验证如下

private async Task<AuthenticationResult> AuthenticateAsync(string[] scopes)
    {
        string error = String.Empty;
        AuthenticationResult authResult = null;

        var accounts = await _clientApp.GetAccountsAsync();
        var firstAccount = accounts.FirstOrDefault();

        try
        {
            authResult = await _clientApp.AcquireTokenSilent(scopes, firstAccount).ExecuteAsync();
        }
        catch (MsalUiRequiredException ex)
        {
            // A MsalUiRequiredException happened on AcquireTokenSilent. 
            // This indicates you need to call AcquireTokenInteractive to acquire a token
            System.Diagnostics.Debug.WriteLine($"MsalUiRequiredException: {ex.Message}");

            try
            {
                authResult = await _clientApp.AcquireTokenInteractive(scopes)
                    .WithAccount(accounts.FirstOrDefault())
                    .WithPrompt(Prompt.SelectAccount)
                    .ExecuteAsync();
            }
            catch (MsalException msalex)
            {
                error += $"Error Acquiring Token:{System.Environment.NewLine}{msalex}" + Environment.NewLine;
            }
        }
        catch (Exception ex)
        {
            error += $"Error Acquiring Token Silently:{System.Environment.NewLine}{ex}" + Environment.NewLine;
        }

        if (string.IsNullOrEmpty(error))
            return authResult;
        else
            throw new AuthenticationException(error);
    }

如果我通过范围

string[] graphsScopes = new string[] { "user.read" };

我可以成功发送电子邮件,但我无法调用我的自定义API,如果我通过了范围

string[] customScopes = new string[] { "api://<MyApiId>/<MyScopeName>" };

我可以拨打我的电话 API 但不能发送电子邮件。

如果我尝试同时添加两者,我只会在 AuthenticationResult 中获取范围数组中第一个出现的范围。

如果我对 AuthenticateAsync 进行两次调用,每个范围调用一次,并使用检索到的两个单独的 AccessTokens 分别调用我的 api 并发送一封电子邮件,一切正常,但我不确定为什么我应该需要在我的应用程序中管理两个不同的访问令牌到 Azure 门户中的一个注册应用程序。

我发现了这个 Multiple resources in a single authorization request 问题,其中提到无法混合来自 Microsoft Graph 和 Outlook 的范围。office365.com 但没有说明为什么或是否同样适用于混合自定义 API 范围和图形范围

静默获取token至少需要调用两次AcquireToken。 这是因为访问令牌仅对一个 API 有效, 由令牌中的听众 (aud) 声明命名。 因此,要调用两个 API,您需要两个不同的访问令牌。

过去在交互式身份验证时为两个不同的 API 指定范围存在问题,但 IIRC 现在应该可以了。 您应该能够使用获得的刷新令牌来获取不同 API 的令牌。 或者更准确地说,您应该能够在交互调用后静默地为另一个 API 获取令牌。