共用方式為


401 ASP.NET Core Web API 中具有 Microsoft Entra 識別碼的未經授權錯誤

當您呼叫使用 Microsoft Entra ID 驗證保護的 ASP.NET Core Web API 時,可能會遇到「401 未經授權」錯誤。 本文提供使用 JwtBearerEvents 來擷取詳細記錄以針對這些錯誤進行疑難解答的指引。

癥狀

您可以使用 [Authorize] 屬性來保護 您的 ASP.NET Core Web API,如下所示:

[Authorize]
public class MyController : ControllerBase
{
    ...
}


public class MyController : ControllerBase
{
   [Authorize]
   public ActionResult<string> Get(int id)
   {
       return "value";
   }
   ...
}

當您呼叫 Web API 時,會傳回「401 未經授權」回應,但訊息不包含錯誤詳細數據。

原因

在下列案例中,API 可能會傳回「401 未經授權」回應:

  • 要求不包含有效的「授權:持有人」令牌標頭。
  • 令牌已過期或錯誤:

解決方法

若要偵錯並解決「401 未經授權」錯誤,請使用 JwtBearerEvents 回呼來擷取並記錄詳細的錯誤資訊。 請遵循下列步驟來實作自定義錯誤處理機制。

類別 JwtBearerEvents 具有下列回呼屬性(依下列順序叫用),可協助您偵錯這些「401 拒絕存取」或「未授權」問題:

步驟 1:啟用個人可識別信息(PII)記錄

根據預設,會停用個人標識資訊 (PII) 記錄。 在 Startup.cs 檔案的 Configure 方法中啟用它以進行偵錯。

謹慎

只有在開發環境中,才使用 'Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true'進行偵錯。 請勿在生產環境中使用它。

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        // The default HSTS value is 30 days. You might want to change this value for production scenarios. See https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }
    // turn on PII logging
    Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;

    app.UseHttpsRedirection();
    app.UseAuthentication();
    app.UseMvc();
}  

步驟 2:建立公用程式方法來格式化例外狀況訊息

新增方法來格式化,並扁平化任何例外狀況訊息,以提升可讀性:

public static string FlattenException(Exception exception)
{
    var stringBuilder = new StringBuilder();
    while (exception != null)
    {
        stringBuilder.AppendLine(exception.Message);
        stringBuilder.AppendLine(exception.StackTrace);
        exception = exception.InnerException;
    }
    return stringBuilder.ToString();
}

步驟 3:實作 JwtBearerEvents 回調

Startup.csConfigureServices方法中配置JwtBearerEvents回呼,來處理身份驗證事件並紀錄錯誤詳情:

public void ConfigureServices(IServiceCollection services)
{
....
    .AddJwtBearer(options =>
    {
        options.Authority = "https://login.microsoftonline.com/<Tenant>.onmicrosoft.com";
        // if you intend to validate only one audience for the access token, you can use options.Audience instead of
        // using options.TokenValidationParameters which allow for more customization.
        // options.Audience = "10e569bc5-4c43-419e-971b-7c37112adf691";

        options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
        {
            ValidAudiences = new List<string> { "<Application ID URI>", "10e569bc5-4c43-419e-971b-7c37112adf691" },
            ValidIssuers = new List<string> { "https://sts.windows.net/<Directory ID>/", "https://sts.windows.net/<Directory ID>/v2.0" }
        };
                
        options.Events = new JwtBearerEvents
        {
            OnAuthenticationFailed = ctx =>
            {
                ctx.Response.StatusCode = StatusCodes.Status401Unauthorized;
                message += "From OnAuthenticationFailed:\n";
                message += FlattenException(ctx.Exception);
                return Task.CompletedTask;
            },

            OnChallenge = ctx =>
            {
                message += "From OnChallenge:\n";
                ctx.Response.StatusCode = StatusCodes.Status401Unauthorized;
                ctx.Response.ContentType = "text/plain";
                return ctx.Response.WriteAsync(message);
            },

            OnMessageReceived = ctx =>
            {
                message = "From OnMessageReceived:\n";
                ctx.Request.Headers.TryGetValue("Authorization", out var BearerToken);
                if (BearerToken.Count == 0)
                    BearerToken = "no Bearer token sent\n";
                message += "Authorization Header sent: " + BearerToken + "\n";
                return Task.CompletedTask;
            },
#For completeness, the sample code also implemented the OnTokenValidated property to log the token claims. This method is invoked when authentication is successful
            OnTokenValidated = ctx =>
            {
                Debug.WriteLine("token: " + ctx.SecurityToken.ToString());
                return Task.CompletedTask;
            }
        };
    });
...
}

範例結果

當您實作 JwtBearerEvents 回呼時,如果發生「401 未經授權」錯誤,響應輸出應包含如以下範例所示的詳細資訊:

OnMessageRecieved:

Authorization Header sent: no Bearer token sent.

如果您使用 API 開發工具來偵錯要求,您應該會收到錯誤詳細數據,如下列螢幕快照所示。

API 開發工具中錯誤詳細數據的螢幕快照。

與我們連絡,以取得說明

如果您有任何問題或需要幫助,提出支援請求,或詢問Azure 社群支援。 您也可以向 Azure 意見反應社群提交產品意見反應。