Configurar o registo em Microsoft.Identity.Web

Microsoft. O Identity.Web integra-se com a infraestrutura de registo do ASP.NET Core. Utilize-o para diagnosticar problemas em várias áreas:

  • Fluxos de autenticação - Início de sessão, terminação de sessão, validação de tokens
  • Aquisição de tokens - Acertos/falhas na cache de tokens, operações MSAL
  • Chamadas de API downstream - pedidos HTTP, aquisição de tokens para APIs
  • Condições de erro - Exceções, falhas de validação

Compreender componentes registados

Componente Origem do Registo Purpose
Microsoft.Identity.Web Lógica de autenticação central Configuração, aquisição de tokens, chamadas API
MSAL.NET Microsoft.Identity.Client Operações de cache de token, validação de autoridade
IdentityModel Validação de token Análise de JWT, validação de assinaturas, extração de declarações
ASP.NET Core Auth Microsoft.AspNetCore.Authentication Operações de cookies, ações de desafio/proibição

Comece a fazer registos

Configuração mínima

Adicione as seguintes entradas de nível de registo a appsettings.json para permitir o registo de identidade.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.Identity": "Information"
    }
  }
}

Isto permite registos de nível de informação para Microsoft.Identity.Web e as suas dependências (MSAL.NET, IdentityModel).

Configuração de desenvolvimento

Para diagnósticos detalhados durante o desenvolvimento:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Identity": "Debug",
      "Microsoft.AspNetCore.Authentication": "Information"
    }
  },
  "AzureAd": {
    "EnablePiiLogging": true  // Development only!
  }
}

Configuração de produção

Para produção, minimize o volume de registos ao capturar erros.

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning",
      "Microsoft": "Warning",
      "Microsoft.Identity": "Warning"
    }
  },
  "AzureAd": {
    "EnablePiiLogging": false  // Never true in production
  }
}

Configurar a filtragem de logs

Filtragem baseada em espaço de nomes

Controla a verbosidade dos registos por namespace. A seguinte configuração define níveis granulares para cada namespace relacionado com identidade:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",

      // General Microsoft namespaces
      "Microsoft": "Warning",
      "Microsoft.AspNetCore": "Warning",

      // Identity-specific namespaces
      "Microsoft.Identity": "Information",
      "Microsoft.Identity.Web": "Information",
      "Microsoft.Identity.Client": "Information",

      // ASP.NET Core authentication
      "Microsoft.AspNetCore.Authentication": "Information",
      "Microsoft.AspNetCore.Authentication.JwtBearer": "Information",
      "Microsoft.AspNetCore.Authentication.OpenIdConnect": "Debug",

      // Token validation
      "Microsoft.IdentityModel": "Warning"
    }
  }
}

Desativar registos específicos

Para silenciar componentes ruidosos sem afetar outros, defina o seu nível logarítmico para None ou Warning:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.Identity.Web": "None",  // Completely disable
      "Microsoft.Identity.Client": "Warning"  // Only errors/warnings
    }
  }
}

Configuração específica do ambiente

Uso appsettings.{Environment}.json para definições por ambiente:

appsettings.Development.json:

{
  "Logging": {
    "LogLevel": {
      "Microsoft.Identity": "Debug"
    }
  },
  "AzureAd": {
    "EnablePiiLogging": true
  }
}

appsettings.Production.json:

{
  "Logging": {
    "LogLevel": {
      "Microsoft.Identity": "Warning"
    }
  },
  "AzureAd": {
    "EnablePiiLogging": false
  }
}

Compreender os níveis de log

O ASP.NET Core define os seguintes níveis logaritários. Escolha o nível que equilibre o detalhe de diagnóstico contra o volume de registos para o seu ambiente.

Níveis de log ASP.NET Core

Nível Usage Volume Produção?
Trace Mais detalhado, em todas as operações Muito alto No
Debug Fluxo detalhado, útil para programadores Alto No
Informações Fluxo geral, eventos chave Moderado Seletiva
Warning Condições inesperadas mas entretanto geridas Baixo Sim
Erro Erros e exceções Muito Baixo Sim
Critical Falhas irrecuperáveis Muito Baixo Sim
Nenhum Desativar o registo de logs Nenhum Seletiva

Mapear MSAL.NET para níveis ASP.NET Core

Nível MSAL.NET ASP.NET Core Equivalente Descrição
Verbose Debug ou Trace Mensagens mais detalhadas
Info Information Eventos de autenticação de chaves
Warning Warning Condições anormais mas controladas
Error Error ou Critical Erros e exceções

Use as seguintes configurações por ambiente.

Desenvolvimento:

{
  "Logging": {
    "LogLevel": {
      "Microsoft.Identity": "Debug",
      "Microsoft.Identity.Client": "Information"
    }
  }
}

Ambiente de Testes:

{
  "Logging": {
    "LogLevel": {
      "Microsoft.Identity": "Information",
      "Microsoft.Identity.Client": "Warning"
    }
  }
}

Produção:

{
  "Logging": {
    "LogLevel": {
      "Microsoft.Identity": "Warning",
      "Microsoft.Identity.Client": "Error"
    }
  }
}

Configurar o registo de PII

Por padrão, o Microsoft.Identity.Web oculta informações de identificação pessoal (PII) dos registos. Ative o registo de PII apenas em ambientes de desenvolvimento para ver todos os detalhes do utilizador.

O que é PII?

A Informação Pessoal Identificável (PII) inclui:

  • Nomes de utilizador, endereços de email
  • Nomes de exibição
  • IDs de objetos, IDs de inquilino
  • Endereços IP
  • Valores de tokens, reivindicações

Aviso de segurança

AVISO: Você e a sua candidatura são responsáveis por cumprir todos os requisitos regulamentares aplicáveis, incluindo os estabelecidos pelo RGPD. Antes de ativar o registo de PII, certifique-se de que consegue lidar com estes dados potencialmente altamente sensíveis em segurança.

Ativar registo de informações PII (apenas para desenvolvimento)

Defina EnablePiiLogging para true no seu ficheiro de configuração de desenvolvimento:

appsettings.Development.json:

{
  "AzureAd": {
    "EnablePiiLogging": true  //  Development/Testing ONLY
  },
  "Logging": {
    "LogLevel": {
      "Microsoft.Identity": "Debug"
    }
  }
}

Controla o registo de PII de forma programática

Alterne o registo das PII com base no ambiente de alojamento:

var builder = WebApplication.CreateBuilder(args);

builder.Services.Configure<MicrosoftIdentityOptions>(options =>
{
    // Only enable PII in Development
    options.EnablePiiLogging = builder.Environment.IsDevelopment();
});

O que muda com as PII ativadas?

Sem registo de PII:

[Information] Token validation succeeded for user '{hidden}'
[Information] Acquired token from cache for scopes '{hidden}'

Com a PII ativada:

[Information] Token validation succeeded for user 'john.doe@contoso.com'
[Information] Acquired token from cache for scopes 'user.read api://my-api/.default'

Redação de PII nos registos

Quando o registo de PII está desativado, os dados sensíveis são substituídos por:

  • {hidden} - Oculta identificadores de utilizador
  • {hash:XXXX} - Mostra o hash em vez do valor real
  • *** - Oculta tokens

Usar identificadores de correlação

Os IDs de correlação rastreiam pedidos de autenticação entre serviços. Inclua-os nos registos e nos tickets de suporte para acelerar a resolução de problemas.

O que são IDs de correlação?

Um ID de correlação é um GUID que identifica de forma única um pedido de autenticação ou aquisição de token ao longo de:

  • A aplicação
  • Plataforma Microsoft Identity
  • Biblioteca MSAL.NET
  • Serviços backend da Microsoft

Obter IDs de correlação

Método 1: A partir do AuthenticationResult

Extraia o ID de correlação de AuthenticationResult após uma aquisição bem-sucedida do token.

using Microsoft.Identity.Web;

public class TodoController : ControllerBase
{
    private readonly ITokenAcquisition _tokenAcquisition;
    private readonly ILogger<TodoController> _logger;

    public TodoController(
        ITokenAcquisition tokenAcquisition,
        ILogger<TodoController> logger)
    {
        _tokenAcquisition = tokenAcquisition;
        _logger = logger;
    }

    [HttpGet]
    public async Task<IActionResult> GetTodos()
    {
        var result = await _tokenAcquisition.GetAuthenticationResultForUserAsync(
            new[] { "user.read" });

        _logger.LogInformation(
            "Token acquired. CorrelationId: {CorrelationId}, Source: {TokenSource}",
            result.CorrelationId,
            result.AuthenticationResultMetadata.TokenSource);

        return Ok(result.CorrelationId);
    }
}

Método 2: A partir de MsalServiceException

Capture o identificador de correlação a partir de MsalServiceException quando a aquisição do token falha.

using Microsoft.Identity.Client;

try
{
    var token = await _tokenAcquisition.GetAccessTokenForUserAsync(
        new[] { "user.read" });
}
catch (MsalServiceException ex)
{
    _logger.LogError(ex,
        "Token acquisition failed. CorrelationId: {CorrelationId}, ErrorCode: {ErrorCode}",
        ex.CorrelationId,
        ex.ErrorCode);

    // Return correlation ID to user for support
    return StatusCode(500, new {
        error = "authentication_failed",
        correlationId = ex.CorrelationId
    });
}

Método 3: Definir um ID de correlação personalizado

Atribua um ID de correlação personalizado para ligar os rastreios da aplicação aos pedidos do Microsoft Entra ID:

[HttpGet("{id}")]
public async Task<IActionResult> GetTodo(int id)
{
    // Use request trace ID as correlation ID
    var correlationId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;

    var todo = await _downstreamApi.GetForUserAsync<Todo>(
        "TodoListService",
        options =>
        {
            options.RelativePath = $"api/todolist/{id}";
            options.TokenAcquisitionOptions = new TokenAcquisitionOptions
            {
                CorrelationId = Guid.Parse(correlationId)
            };
        });

    _logger.LogInformation(
        "Called downstream API. TraceId: {TraceId}, CorrelationId: {CorrelationId}",
        HttpContext.TraceIdentifier,
        correlationId);

    return Ok(todo);
}

Forneça IDs de correlação para suporte

Quando contactar o suporte da Microsoft, forneça os seguintes detalhes:

  1. ID de correlação - A partir de logs ou exceção
  2. Carimbo temporal - Quando ocorreu o erro (UTC)
  3. ID de Inquilino - O seu inquilino Microsoft Entra ID
  4. Código de erro - Se aplicável (por exemplo, AADSTS50058)

Exemplo de pedido de suporte:

Subject: Token acquisition failing for user.read scope

Correlation ID: 12345678-1234-1234-1234-123456789012
Timestamp: 2025-01-15 14:32:45 UTC
Tenant ID: contoso.onmicrosoft.com
Error Code: AADSTS50058

Ativar o registo da cache de tokens

O registo de cache de tokens ajuda-te a compreender o comportamento de acertos/erros da cache e a diagnosticar problemas de desempenho com caches distribuídas.

Ativar diagnósticos de cache de token

Para aplicações .NET Framework ou .NET Core que utilizam caches de tokens distribuídos, configure registos detalhados:

using Microsoft.Extensions.Logging;
using Microsoft.Identity.Web.TokenCacheProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDistributedTokenCaches();

// Enable detailed token cache logging
builder.Services.AddLogging(configure =>
{
    configure.AddConsole();
    configure.AddDebug();
})
.Configure<LoggerFilterOptions>(options =>
{
    options.MinLevel = LogLevel.Debug;  // Detailed cache operations
});

Exemplos de registos de cache de tokens

Impacto do cache:

[Debug] Token cache: Token found in cache for scopes 'user.read'
[Information] Token source: Cache

Erro de cache:

[Debug] Token cache: No token found in cache for scopes 'user.read'
[Information] Token source: IdentityProvider
[Debug] Token cache: Token stored in cache

Resolução de problemas de caches distribuídas

Ative o registo específico do fornecedor para diagnosticar problemas de conectividade e desempenho da cache.

Cache Redis:

builder.Services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = builder.Configuration["Redis:ConnectionString"];
});

// Enable Redis logging
builder.Services.AddLogging(configure =>
{
    configure.AddFilter("Microsoft.Extensions.Caching", LogLevel.Debug);
});

SQL Server cache:

Configure a cache distribuída do SQL Server com registo:

builder.Services.AddDistributedSqlServerCache(options =>
{
    options.ConnectionString = builder.Configuration["SqlCache:ConnectionString"];
    options.SchemaName = "dbo";
    options.TableName = "TokenCache";
});

// Enable SQL cache logging
builder.Services.AddLogging(configure =>
{
    configure.AddFilter("Microsoft.Extensions.Caching.SqlServer", LogLevel.Information);
});

Resolver problemas comuns

Use os seguintes cenários para diagnosticar problemas frequentes de autenticação e autorização.

Cenários comuns de registo

Cenário 1: Falhas na validação do token

Sintoma: 401 Respostas não autorizadas

Ativar o registo detalhado:

{
  "Logging": {
    "LogLevel": {
      "Microsoft.AspNetCore.Authentication.JwtBearer": "Debug",
      "Microsoft.IdentityModel": "Information"
    }
  }
}

Pesquisar:

[Information] Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:
  Failed to validate the token.
[Debug] Microsoft.IdentityModel.Tokens: IDX10230: Lifetime validation failed.
  The token is expired.

Cenário 2: Falhas na aquisição de tokens

Sintoma:MsalServiceException ou MsalUiRequiredException

Ativar o registo detalhado:

{
  "Logging": {
    "LogLevel": {
      "Microsoft.Identity.Web": "Debug",
      "Microsoft.Identity.Client": "Information"
    }
  }
}

Pesquisar:

[Error] Microsoft.Identity.Web: Token acquisition failed.
  ErrorCode: invalid_grant, CorrelationId: {guid}
[Information] Microsoft.Identity.Client: MSAL returned exception:
  AADSTS50058: Silent sign-in failed.

Cenário 3: Falhas nas chamadas de API a jusante

Sintoma: HTTP 502 ou erros de timeout ao chamar APIs a jusante

Ativar o registo detalhado:

{
  "Logging": {
    "LogLevel": {
      "Microsoft.Identity.Abstractions": "Debug",
      "System.Net.Http": "Information"
    }
  }
}

Adicione login personalizado no seu controlador para capturar erros da API a jusante:

[HttpGet]
public async Task<IActionResult> GetUserProfile()
{
    try
    {
        _logger.LogInformation("Acquiring token for Microsoft Graph");

        var user = await _downstreamApi.GetForUserAsync<User>(
            "MicrosoftGraph",
            options => options.RelativePath = "me");

        _logger.LogInformation(
            "Successfully retrieved user profile for {UserPrincipalName}",
            user.UserPrincipalName);

        return Ok(user);
    }
    catch (MsalUiRequiredException ex)
    {
        _logger.LogWarning(ex,
            "User interaction required. CorrelationId: {CorrelationId}",
            ex.CorrelationId);
        return Challenge();
    }
    catch (HttpRequestException ex)
    {
        _logger.LogError(ex, "Failed to call Microsoft Graph API");
        return StatusCode(502, "Downstream API error");
    }
}

Interpretar padrões logarítmicos

Os exemplos seguintes mostram a saída típica de registo para eventos comuns de autenticação.

Fluxo de autenticação bem-sucedido:

[Info] Authentication scheme OpenIdConnect: Authorization response received
[Debug] Correlation id: {guid}
[Info] Authorization code received
[Info] Token validated successfully
[Info] Authentication succeeded for user: {user}

Consentimento necessário:

[Warning] Microsoft.Identity.Web: Incremental consent required
[Info] AADSTS65001: User consent is required for scopes: {scopes}
[Info] Redirecting to consent page

Atualização do token:

[Debug] Token expired, attempting silent token refresh
[Info] Token source: IdentityProvider
[Info] Token refreshed successfully

Agregar registos junto a fornecedores externos

Encaminhe os registos de identidade para uma plataforma centralizada de registo para monitorização e alerta.

Integração com o Application Insights:

Envie telemetria de identidade para Application Insights com enriquecimento de ID de correlação:

using Microsoft.ApplicationInsights.Extensibility;

builder.Services.AddApplicationInsightsTelemetry();

// Enrich telemetry with correlation IDs
builder.Services.AddSingleton<ITelemetryInitializer, CorrelationIdTelemetryInitializer>();

Integração com Serilog:

Configure o Serilog para capturar registos de identidade para as saídas de ficheiros da consola e roll:

using Serilog;

Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Information()
    .MinimumLevel.Override("Microsoft.Identity", Serilog.Events.LogEventLevel.Debug)
    .Enrich.FromLogContext()
    .WriteTo.Console()
    .WriteTo.File("logs/identity-.txt", rollingInterval: RollingInterval.Day)
    .CreateLogger();

builder.Host.UseSerilog();

Siga as melhores práticas de registo de logs

Aplique estas práticas para manter os seus registos de identidade seguros, úteis e eficazes.

Coisas a Fazer

1. Utilizar registo estruturado:

Passe valores como parâmetros nomeados para que os agregadores de logs possam indexá-los e consultá-los:

_logger.LogInformation(
    "Token acquired for user {UserId} with scopes {Scopes}",
    userId, string.Join(" ", scopes));

2. IDs de correlação logarítmica:

Inclua sempre o ID de correlação nos registos de erro para simplificar investigações de suporte:

_logger.LogError(ex,
    "Operation failed. CorrelationId: {CorrelationId}",
    ex.CorrelationId);

3. Use níveis logarítmicos apropriados:

Ajusta o nível do log à gravidade e ao público:

_logger.LogDebug("Detailed diagnostic info");      // Development
_logger.LogInformation("Key application events");  // Selective production
_logger.LogWarning("Unexpected but handled");      // Production
_logger.LogError(ex, "Operation failed");          // Production

4. Limpar registos em produção:

Mascarar valores sensíveis antes de os escrever nos registos de produção:

var sanitizedEmail = environment.IsProduction()
    ? MaskEmail(email)
    : email;
_logger.LogInformation("Processing request for {Email}", sanitizedEmail);

Coisas a não fazer

1. Não ative Informações de Identificação Pessoal (PII) em produção:

//  Wrong
"EnablePiiLogging": true  // In production config!

//  Correct
"EnablePiiLogging": false

2. Não registar segredos:

//  Wrong
_logger.LogInformation("Token: {Token}", accessToken);

//  Correct
_logger.LogInformation("Token acquired, expires: {ExpiresOn}", expiresOn);

3. Não use registo verboso em produção:

//  Wrong - production appsettings.json
"Microsoft.Identity": "Debug"

//  Correct
"Microsoft.Identity": "Warning"