代表api不是用户从另一个WebAp获取401 Unauthorized调用WebApi

问题描述

我们在 Azure 中有许多代表用户调用的 ASPNET Core Web API。该用户通常已登录 ASPNET 网站,也在 Azure 中。

我们正在推出审计服务。感觉应该代表调用服务而不是经过身份验证的用户调用它。

  • 审计服务在 Azure AD 中有一个关联的应用注册
  • 审计服务有一个名为“access_as_application”的范围,虽然看过有关“.default”范围的文档,但我不确定我是否需要一个范围
  • 已将调用应用程序(ASPNET Core 网站)添加到“授权的客户端应用程序”部分,以针对前面提到的范围

调用应用程序中,我通过使用 GetAccesstokenForAppAsync 获得了应用程序的访问令牌,而不是用户的访问令牌。

var accesstoken = await this.tokenAcquisition.GetAccesstokenForAppAsync(this.auditApiScope);
System.Diagnostics.Debug.WriteLine($"access token-{accesstoken}");
this.httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",accesstoken);
this.httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

目前我正在本地开发机器上运行调用应用程序和审计服务。

当我打电话给审计服务时,我收到了 401 Unauthorized

var response = await this.httpClient.PostAsync($"{this.auditApiBaseAddress}v1/entries",requestContent);

更新

我已通过应用清单将调用应用程序的 Azure 广告应用程序 ID 添加为审核服务上的 kNownClientApplication。这并没有阻止 401

"kNownClientApplications": [
        "7ac7f49d-e9fa-4e1b-95b2-03e0e1981f58"
    ],

更新 2

我可以看到在 Visual Studio 中运行的服务实例正在报告堆栈跟踪。它指的是 IDW10201 问题。

System.UnauthorizedAccessException: IDW10201: Neither scope or roles claim was found in the bearer token. 
   at Microsoft.Identity.Web.MicrosoftIdentityWebApiAuthenticationBuilderExtensions.<>c__displayClass3_1.<<AddMicrosoftIdentityWebApiImplementation>b__1>d.MoveNext()
--- End of stack trace from prevIoUs location where exception was thrown ---
   at Microsoft.Identity.Web.MicrosoftIdentityWebApiAuthenticationBuilder.<>c__displayClass14_0.<<CallsWebApiImplementation>b__1>d.MoveNext()
--- End of stack trace from prevIoUs location where exception was thrown ---
   at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
   at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
   at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.AuthenticateAsync()
   at Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context,String scheme)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

有什么想法吗?

解决方法

您当前应该执行服务器到服务器的交互,即没有用户参与。因此,您的服务器应用需要创建一个 appRole,然后将应用角色作为应用权限授予客户端应用

首先需要暴露Azure保护的服务器应用的api,可以按照如下流程进行配置:

Azure 门户>应用注册>公开 API>添加范围>添加客户端应用

enter image description here

然后您需要创建服务器应用程序的 appRole,然后将该角色作为应用程序权限授予客户端应用程序。

enter image description here

接下来,转到客户端应用程序>API 权限>添加权限>我的 API>您的 API 应用程序。

enter image description here

最后,您需要在没有用户登录的情况下使用 client credential flow 获取访问令牌:

enter image description here

解析token:

enter image description here

,

虽然我已将 Carl Zhao 的贡献标记为答案,但我发现屏幕截图有点难以理解,所以这是我试图使之更清晰一些的尝试。

在这种情况下,我们希望在 Azure Ad 注册应用程序(客户端)和另一个 Azure Ad 注册应用程序(审计服务)范围之间进行身份验证,这不是解决方案。我们需要公开 appRole,而不是公开范围。

公开然后请求访问应用角色所需的步骤是

  1. 应用注册 -> 审核服务 -> 管理 -> 应用角色 -> 创建应用角色
  2. 创建应用程序角色时,确保允许的成员类型为“应用程序”
  3. 现在转到应用注册 -> YourClientApplication -> Api 权限 -> 添加权限
  4. 我希望审计服务出现在“请求 API 权限面板”中的“我的 API”下。我没有,我可以请求对先前创建的 AppRole 进行许可的唯一方法是在“我的组织使用的 API”下的搜索框中输入审核服务的 AppId
  5. 选择审核服务后,我选择了“应用程序权限”而不是“委派权限”,然后选择了特定角色

一旦客户端应用程序被授予访问权限,我们就需要编写代码来获取访问令牌。使用 Mictosoft.Identity.Web 库

var accessToken = await this.tokenAcquisition.GetAccessTokenForAppAsync(this.auditApiScope);
System.Diagnostics.Debug.WriteLine($"access token-{accessToken}");
this.httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",accessToken);
this.httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

注意调用 GetAccessTokenForAppAsync 而不是 GetAccessTokenForUserAsync。 GetAccessTokenForAppAsync 仍然需要一个范围,但是如前所述,不需要自定义范围。范围是“.default”,所以在我们的例子中传递给该调用的字符串是 https://ourdomain/audit-service/.default”,它是我们的 App ID URI 加上“.default”