Xamarin 应用程序的 Azure AD 身份验证无法在下游 Web API 上进行身份验证

jav*_*vaj 5 c# azure-active-directory .net-core

我构建了一个 ASP.NET core Web 应用程序,调用 ASP.NET Core Web API,该 API 使用 Azure AD 进行保护,如此处所述。

我还构建了一个 Xamarin 移动应用程序,该应用程序对 Web 应用程序的 Azure 应用程序服务进行身份验证并利用下游 Web API,如此处所述。

Web App可以毫无问题地访问API;但是,Xamarin 应用程序失败并显示 HTTP 响应消息:未经授权。

利用此处Microsoft Identity 团队的指导,我能够找到失败的原因。

Microsoft.AspNetCore.Authorization.DefaultAuthorizationService: Information: Authorization failed. These requirements were not met:
DenyAnonymousAuthorizationRequirement: Requires an authenticated user.
Run Code Online (Sandbox Code Playgroud)

需求的源代码片段显示了失败的地方。具体来说,它是在 IsAuthenticated 检查上。

public class DenyAnonymousAuthorizationRequirement : AuthorizationHandler<DenyAnonymousAuthorizationRequirement>, IAuthorizationRequirement
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, DenyAnonymousAuthorizationRequirement requirement)
    {
        var user = context.User;
        var userIsAnonymous =
            user?.Identity == null ||
            !user.Identities.Any(i => i.IsAuthenticated);
        if (!userIsAnonymous)
        {
            context.Succeed(requirement);
        }
        return Task.CompletedTask;
    }
Run Code Online (Sandbox Code Playgroud)

跟踪正在运行的 Web 应用程序中的代码,会生成如下所示的上下文。关键点是 GetAccessTokenForUserAsync 方法代表用户帐户获取下游 API 的访问令牌,该帐户的声明是在控制器的 HttpContext 参数的 User 成员中提供的。

...
builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration);

await PrepareAuthenticatedClient();

var response = await httpClient.GetAsync($"https://example.com/api/mycontroller");
...

private async Task PrepareAuthenticatedClient()
{
    var accessToken = await tokenAcquisition.GetAccessTokenForUserAsync(new[] { "api://xxxx/.default"});
    httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
    httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

跟踪失败的 Xamarin 应用程序的代码,生成的上下文如下所示。

...
PCA = PublicClientApplicationBuilder
   .Create(ClientID)
   .WithTenantId(TenantID)
   .WithRedirectUri($"msal{ClientID}://auth")
   .Build();

authResult = await App.PCA.AcquireTokenInteractive("api://xxxx/.default").ExecuteAsync();

var result = Network.GetHttpContentWithTokenAsync(authToken);
...

public async Task<string> GetHttpContentWithTokenAsync(string token)
{
    HttpClient client = new HttpClient();
    HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Get, "https://example.com/api/mycontroller");
    message.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
    HttpResponseMessage response = await client.SendAsync(message);
    string responseString = await response.Content.ReadAsStringAsync();
    return responseString;
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

如何让经过身份验证的用户进入 Xamarin 应用程序的 HTTP 上下文?