尝试使用 MSAL、OpenID Connect 访问受保护的 Web API 时出现 401 未经授权

问题描述 投票:0回答:1

我需要从我的客户端应用程序访问受保护的 Web API(托管在 Azure 上)。 当我打开我的客户端应用程序时,我正在检索访问令牌,然后我将其添加到请求标头中,但 API 返回

401 unauthorized
.

这就是我在客户端上获取访问令牌的方式

public async Task<string> GetToken()
        {
            var authorizationUri = new Uri($@"https://login.microsoftonline.com/{AUTHORITY}");
            var pca = PublicClientApplicationBuilder.Create(CLIENTID)
               .WithAuthority(authorizationUri)
               //.WithAuthority(AadAuthorityAudience.AzureAdAndPersonalMicrosoftAccount)
               .WithRedirectUri(REDIRECTURL).Build();

            // 2. GetAccounts
            var accounts = await pca.GetAccountsAsync();
            var accountToLogin = PublicClientApplication.OperatingSystemAccount;
            try
            {
                // 3. AcquireTokenSilent 
                var authResult = await pca.AcquireTokenSilent(new[] { "api://..api-id../access_as_user" }, accountToLogin) 
                .ExecuteAsync();                

                return authResult.AccessToken;
            }
            catch (MsalUiRequiredException) 
            {
                // 5. AcquireTokenInteractive
                var authResult = await pca.AcquireTokenInteractive(new[] { "api://..api-id../access_as_user" }) 
                .WithAccount(accountToLogin)  
                .ExecuteAsync();

                return authResult.AccessToken;
            }
        }

这就是我调用 Web API 的方式

public async Task<string> GetForecast()
{
    var access = new ServiceAccess();
    var token = await access.GetToken();

    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    client.DefaultRequestHeaders.Authorization =
        new AuthenticationHeaderValue("Bearer", token);

    using HttpResponseMessage response = await client.GetAsync("https://my-api.azurewebsites.net/api/weatherforecast");
    response.EnsureSuccessStatusCode();
    ...
}   

这是 web api 的身份验证配置

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: "mypolicy",
        policy =>
        {
            policy.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod();
        });
});

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options => builder.Configuration.Bind("AzureAd", options));

当我在 jwt.io 中检查令牌的内容时,我没有发现任何问题。

{
  "aud": "my web API id",
  "iss": "https://login.microsoftonline.com/my-tenant-id/v2.0",
  "iat": 1675018002,
  "nbf": 1675018002,
  "exp": 1675022027,
  "aio": "....",
  "azp": "my web API id",
  "azpacr": "0",
  "idp": "live.com",
  "name": "...",
  "oid": "some guid",
  "preferred_username": "[email protected]",
  "rh": "???",
  "scp": "access_as_user",
  "sub": "???",
  "tid": "my tenant id",
  "uti": "???",
  "ver": "2.0"
}

在 SO 中找到了一些类似的帖子,但它们似乎都没有提到我的问题

  1. 错误的观众 - 在我的例子中,Token 的观众包含 Web API 的 ID
  2. 试过这本手册
.net openid msal
1个回答
1
投票

调试令牌问题的一种方法是在 AddJwtBearer 选项中启用以下标志:

    /// <summary>
    /// Defines whether the token validation errors should be returned to the caller. 
    /// Default set to true.
    /// </summary>
    public bool IncludeErrorDetails { get; set; } = true;

如果设置为 true,它将在响应头中包含更多错误详细信息:

HTTP/1.1 401 Unauthorized
Date: Sun, 02 Aug 2020 11:19:06 GMT
WWW-Authenticate: Bearer error="invalid_token", error_description="The signature is invalid"

另一种方法是查看 AddJwtBearer 的日志。

要访问日志文件,您可以将调试级别更改为 Microsoft.AspNetCore.Authentication 命名空间的调试或跟踪。如果您从 appsettings 配置日志记录,您可以使用:

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information",
      "Microsoft.AspNetCore.Authentication": "Debug",
      "Microsoft.AspNetCore.Authorization": "Trace"
    }
  }
}

为了补充这个答案,我写了一篇博客文章,详细介绍了这个主题: 解决 ASP.NET Core 中的 JwtBearer 身份验证问题

© www.soinside.com 2019 - 2024. All rights reserved.