Skonfiguruj logowanie w Microsoft. Identity.Web

Microsoft. Usługa Identity.Web integruje się z infrastrukturą rejestrowania ASP.NET Core. Użyj go do diagnozowania problemów między:

  • Przepływy uwierzytelniania — logowanie, wylogowywanie, walidacja tokenu
  • Pozyskiwanie tokenów — trafienia/chybienia pamięci podręcznej tokenu, operacje MSAL
  • Wywołania interfejsu API podrzędnego — żądania HTTP, pobieranie tokenów do interfejsów API
  • Warunki błędu — wyjątki, błędy walidacji

Omówienie zarejestrowanych składników

Składnik Źródło dziennika Purpose
Microsoft. Identity.Web Podstawowa logika uwierzytelniania Konfiguracja, pozyskiwanie tokenów, wywołania interfejsu API
MSAL.NET Microsoft.Identity.Client Operacje pamięci podręcznej tokenu, walidacja autorytetu
Model tożsamości Walidacja tokenu Analizowanie JWT, walidacja podpisu, wyodrębnianie oświadczeń
ASP.NET Core Auth Microsoft.AspNetCore.Authentication Operacje na plikach cookie, wyzwanie/zakaz akcji

Rozpocznij logowanie

Minimalna konfiguracja

Dodaj następujące wpisy na poziomie dziennika do appsettings.json, aby włączyć rejestrowanie tożsamości.

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

Umożliwia to logowanie na poziomie informacji dla Microsoft.Identity.Web i jego zależności (MSAL.NET, IdentityModel).

Konfiguracja programowania

Aby uzyskać szczegółową diagnostykę podczas programowania:

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

Konfiguracja produkcyjna

W przypadku środowiska produkcyjnego zminimalizuj wolumin dziennika podczas przechwytywania błędów:

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

Konfigurowanie filtrowania dzienników

Filtrowanie oparte na przestrzeni nazw

Kontrolowanie szczegółowości dziennika według przestrzeni nazw. Poniższa konfiguracja ustawia szczegółowe poziomy dla każdej przestrzeni nazw powiązanej z tożsamością:

{
  "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"
    }
  }
}

Wyłączanie określonego rejestrowania

Aby wyciszyć hałaśliwe składniki bez wpływu na inne komponenty, ustaw ich poziom logowania na None lub Warning:

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

Konfiguracja specyficzna dla środowiska

Użyj appsettings.{Environment}.json dla ustawień poszczególnych środowisk.

appsettings.Development.json:

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

appsettings.Production.json:

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

Zrozumieć poziomy logów

ASP.NET Core definiuje następujące poziomy dziennika. Wybierz poziom, który równoważy szczegóły diagnostyczne względem woluminu dziennika dla środowiska.

Poziomy dziennika ASP.NET Core

Level Użycie Volume Produkcja?
Śledzenie Najbardziej szczegółowa, każda operacja Bardzo wysoka Nie.
Debug Szczegółowy przepływ przydatny dla deweloperów High Nie.
Informacje Ogólny przepływ, kluczowe zdarzenia Umiarkowane Selektywne
Ostrzeżenie Nieoczekiwane, ale obsługiwane sytuacje Low Yes
Błąd Błędy i wyjątki Bardzo niski Yes
Krytyczne Nieodwracalne błędy Bardzo niski Yes
Brak Wyłącz rejestrowanie Żadne Selektywne

Mapuj MSAL.NET na poziomy ASP.NET Core

poziom MSAL.NET odpowiednik ASP.NET Core Opis
Verbose Debug lub Trace Najbardziej szczegółowe komunikaty
Info Information Zdarzenia uwierzytelniania kluczy
Warning Warning Nietypowe, ale obsługiwane warunki
Error Error lub Critical Błędy i wyjątki

Użyj następujących konfiguracji na środowisko.

Rozwój:

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

Etap przygotowawczy:

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

Produkcji:

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

Konfigurowanie rejestrowania informacji umożliwiających identyfikację osób

Domyślnie, Microsoft.Identity.Web ukrywa dane osobowe (PII) z dzienników logowania. Włącz rejestrowanie danych osobowych tylko w środowiskach deweloperskich, aby wyświetlić pełne szczegóły użytkownika.

Co to jest dane osobowe?

Dane osobowe (PII) obejmują:

  • Nazwy użytkowników, adresy e-mail
  • Nazwy wyświetlane
  • Identyfikatory obiektów, identyfikatory dzierżawców
  • Adresy IP
  • Wartości tokenu, oświadczenia

Ostrzeżenie o zabezpieczeniach

OSTRZEŻENIE: Ty i Twoja aplikacja są odpowiedzialni za przestrzeganie wszystkich obowiązujących wymagań prawnych, w tym tych określonych przez RODO. Przed włączeniem rejestrowania danych PII upewnij się, że potrafisz bezpiecznie obsługiwać te dane, które mogą być potencjalnie bardzo poufne.

Włącz rejestrowanie danych PII (tylko rozwój)

Ustaw EnablePiiLogging na true w pliku konfiguracji roboczej:

appsettings.Development.json:

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

Programowe kontrolowanie zapisywania osobistych informacji identyfikacyjnych (PII)

Przełącz rejestrowanie PII w zależności od środowiska hostingu.

var builder = WebApplication.CreateBuilder(args);

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

Jakie zmiany zachodzą po włączeniu PII (danych osobowych)?

Bez rejestrowania danych PII:

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

Po włączeniu identyfikatora PII:

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

Redakcja danych PII w dziennikach

Po wyłączeniu rejestrowania danych PII, poufne dane są zastępowane innymi wartościami:

  • {hidden} - Ukrywa identyfikatory użytkowników
  • {hash:XXXX} - Pokazuje skrót zamiast wartości rzeczywistej
  • *** - Zaciemnia tokeny

Używanie identyfikatorów korelacji

Identyfikatory korelacji śledzą żądania uwierzytelniania między usługami. Dołącz je do dzienników i zgłoszeń pomocy technicznej, aby przyspieszyć rozwiązywanie problemów.

Co to są identyfikatory korelacji?

Identyfikator korelacji to identyfikator GUID , który jednoznacznie identyfikuje żądanie uwierzytelniania lub pozyskiwania tokenu w ramach:

  • Twoja aplikacja
  • platforma Microsoft Identity
  • biblioteka MSAL.NET
  • usługi zaplecza Microsoft

Uzyskiwanie identyfikatorów korelacji

Metoda 1. Z elementu AuthenticationResult

Wyodrębnij identyfikator korelacji z AuthenticationResult po pomyślnym pozyskaniu tokenu.

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

Metoda 2: z MsalServiceException

Przechwyć identyfikator korelacji z MsalServiceException gdy pozyskiwanie tokenu się nie powiedzie.

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

Metoda 3. Ustawianie niestandardowego identyfikatora korelacji

Przypisz niestandardowy identyfikator korelacji, aby połączyć ślady aplikacji z żądaniami 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);
}

Podaj identyfikatory korelacji na potrzeby obsługi

Po skontaktowaniu się z pomocą techniczną Microsoft podaj następujące informacje:

  1. Identyfikator korelacji — z dzienników lub wyjątków
  2. Sygnatura czasowa — kiedy wystąpił błąd (UTC)
  3. Identyfikator dzierżawcy — Twoja dzierżawa Microsoft Entra ID
  4. Kod błędu — jeśli ma zastosowanie (np. AADSTS50058)

Przykładowy wniosek o pomoc techniczną:

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

Włącz rejestrowanie pamięci podręcznej tokenów

Rejestrowanie pamięci podręcznej tokenów pomaga zrozumieć zachowanie trafień i chybień pamięci podręcznej oraz zdiagnozować problemy z wydajnością rozproszonych pamięci podręcznych.

Włącz diagnostykę pamięci podręcznej tokenów

W przypadku aplikacji .NET Framework lub .NET Core korzystających z rozproszonych pamięci podręcznych tokenów skonfiguruj szczegółowe rejestrowanie:

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

Przykłady logów pamięci podręcznej tokenów

Trafienie pamięci podręcznej:

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

Brak pamięci podręcznej:

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

Diagnostyka rozproszonych pamięci podręcznych

Włącz rejestrowanie specyficzne dla dostawcy, aby zdiagnozować problemy z łącznością i wydajnością pamięci podręcznej.

Pamięć podręczna 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:

Konfigurowanie rozproszonej pamięci podręcznej SQL Server z logowaniem:

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

Rozwiązywanie typowych problemów

Skorzystaj z poniższych scenariuszy, aby zdiagnozować częste problemy z uwierzytelnianiem i autoryzacją.

Typowe scenariusze rejestrowania

Scenariusz 1. Niepowodzenia weryfikacji tokenu

Objaw: 401 Nieautoryzowane odpowiedzi

Włącz szczegółowe rejestrowanie:

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

Wyszukaj:

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

Scenariusz 2. Niepowodzenia pozyskiwania tokenów

Objawem:MsalServiceException Lub MsalUiRequiredException

Włącz szczegółowe rejestrowanie:

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

Wyszukaj:

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

Scenariusz 3. Błędy wywołań interfejsu API podrzędnego

Objaw: Błędy HTTP 502 lub przekroczenia limitu czasu podczas wywoływania podrzędnych interfejsów API

Włącz szczegółowe rejestrowanie:

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

Dodaj niestandardowe rejestrowanie w kontrolerze, aby przechwytywać błędy w zewnętrznych interfejsach API.

[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");
    }
}

Interpretowanie wzorców dzienników

W poniższych przykładach przedstawiono typowe dane wyjściowe dziennika dla typowych zdarzeń uwierzytelniania.

Przepływ pomyślnego uwierzytelniania:

[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}

Wymagana zgoda:

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

Odświeżanie tokenu:

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

Agregowanie dzienników przy użyciu dostawców zewnętrznych

Przekazywanie dzienników tożsamości do scentralizowanej platformy rejestrowania na potrzeby monitorowania i zgłaszania alertów.

Integracja usługi Application Insights:

Wyślij telemetrię tożsamości do usługi Application Insights z wzbogaconym identyfikatorem korelacji:

using Microsoft.ApplicationInsights.Extensibility;

builder.Services.AddApplicationInsightsTelemetry();

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

Integracja z usługą Serilog:

Skonfiguruj usługę Serilog, aby przechwycić dzienniki tożsamości w danych wyjściowych konsoli i pliku rolkowego:

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

Postępuj zgodnie z najlepszymi rozwiązaniami dotyczącymi rejestrowania

Zastosuj te rozwiązania, aby zapewnić bezpieczeństwo, przydatne i wydajne dzienniki tożsamości.

Rzeczy, które należy robić

1. Użyj rejestrowania strukturalnego:

Przekaż wartości jako nazwane parametry, aby agregatory dzienników mogły je indeksować i wykonywać względem nich zapytania:

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

2. Identyfikatory korelacji logów:

Zawsze dołączaj identyfikator korelacji w dziennikach błędów, aby uprościć badania pomocy technicznej:

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

3. Użyj odpowiednich poziomów dziennika:

Dopasuj poziom dziennika do poziomu ważności i odbiorców.

_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. Sanityzacja dzienników w środowisku produkcyjnym:

Maskuj poufne wartości przed zapisaniem ich w dziennikach produkcyjnych:

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

Czego nie robić

1. Nie włączaj danych osobowych w środowisku produkcyjnym:

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

//  Correct
"EnablePiiLogging": false

2. Nie rejestruj wpisów tajnych:

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

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

3. Nie używaj rozbudowanego rejestrowania w środowisku produkcyjnym:

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

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