Compartilhar via


401 Erros não autorizados na API Web do ASP.NET Core com a ID do Microsoft Entra

Ao chamar uma API Web do ASP.NET Core protegida usando a autenticação da ID do Microsoft Entra, você pode encontrar um erro "401 Não autorizado". Este artigo fornece diretrizes para usar JwtBearerEvents para capturar logs detalhados para solucionar esses erros.

Sintomas

Use o [Authorize] atributo para proteger sua API Web do ASP.NET Core, da seguinte maneira:

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

Ou


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

Quando você chama a API Web, uma resposta "401 Não autorizada" é retornada, mas a mensagem não contém detalhes de erro.

Motivo

A API pode retornar uma resposta "401 Não autorizada" nos seguintes cenários:

  • A solicitação não inclui um cabeçalho de token válido "Autorização: Portador".
  • O token expirou ou está incorreto:
    • O token é emitido para um recurso diferente.
    • As declarações de token não atendem aos critérios de validação de token do aplicativo, conforme definido na classe JwtBearerOptions.TokenValidationParameters .

Solução

Para depurar e resolver erros "401 Não Autorizado", utilize os JwtBearerEvents callbacks para capturar e registrar informações detalhadas sobre o erro. Siga estas etapas para implementar um mecanismo personalizado de tratamento de erros.

A JwtBearerEvents classe tem as seguintes propriedades de retorno de chamada (invocadas na seguinte ordem) que podem ajudá-lo a depurar esses problemas de "Erro 401: Acesso Negado" ou "Não Autorização":

  • OnMessageRecieved é chamado primeiro para cada solicitação.
  • OnAuthenticationFailed será chamado se o token não passar nos critérios de validação de token do aplicativo.
  • OnChallenge é chamado por último antes de uma resposta "401" ser retornada.

Etapa 1: Habilitar o registro em log de PII

Por padrão, o registro em log de PII (informações de identificação pessoal) está desabilitado. Habilite-o no método Configurar do arquivo Startup.cs para depuração.

Cuidado

Utilize 'Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true' somente em um ambiente de desenvolvimento para depuração. Não o use em um ambiente de produção.

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();
}  

Etapa 2: Criar um método utilitário para formatar mensagens de exceção

Adicione um método para formatar e nivele as mensagens de exceção para obter melhor legibilidade:

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();
}

Etapa 3: Implementar retornos de chamada JwtBearerEvents

Configure os JwtBearerEvents callbacks no ConfigureServices método de Startup.cs para lidar com eventos de autenticação e detalhes de erro no log.

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;
            }
        };
    });
...
}

Resultados de exemplo

Quando você implementa JwtBearerEvents retornos de chamada, se ocorrer um erro "401 Não autorizado", a saída da resposta deverá incluir detalhes, conforme o exemplo a seguir:

OnMessageRecieved:

Authorization Header sent: no Bearer token sent.

Se você usar a ferramenta de desenvolvimento de API para depurar a solicitação, deverá receber detalhes do erro, conforme mostrado na captura de tela a seguir.

Captura de tela dos detalhes do erro na ferramenta de desenvolvimento de API.

Entre em contato conosco para obter ajuda

Se você tiver dúvidas ou precisar de ajuda, crie uma solicitação de suporte ou peça ajuda à comunidade de suporte do Azure. Você também pode enviar comentários sobre o produto para a comunidade de comentários do Azure.