在单个 IPublicClientApplication.AcquireTokenSilent 调用中混合图形和自定义



我有一个应用程序,需要访问自定义API,并且能够通过Graphs 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 进行两次调用,每个范围一个,并使用检索到的两个单独的访问令牌来分别调用我的 api 并发送电子邮件,一切正常,但我不确定为什么我需要在我的应用程序中管理两个不同的访问令牌到 Azure 门户中的一个注册应用程序。

我在单个授权请求问题中找到了这个多个资源,该问题提到无法混合来自 Microsoft 图形和 outlook.office365.com 的范围,但没有说明为什么或是否同样适用于混合自定义 API 范围和图形范围

至少在以静默方式获取代币时,您需要调用 AcquireToken 两次。 这是因为访问令牌仅对一个 API 有效, 由令牌中的受众 (AUD( 声明命名。 因此,要调用两个 API,您需要两个不同的访问令牌。

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

最新更新