代表 api(不是用户)从另一个 Web 应用程序获取 401 未经授权调用 Web Api

Get 401 Unauthorised calling WebApi from another WebAp on behalf of api (not user)

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

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

在调用应用程序中,我使用 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 Ad App 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>添加范围>添加客户端应用程序

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

下一步,转到客户端应用程序>API权限>添加权限>我的APIs >你的 api 申请。

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

解析token:

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

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

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

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

客户端应用程序获得访问权限后,我们需要编写代码获取访问令牌。使用 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”