Microsoft.Identity.Web에서 로깅을 구성합니다.

Microsoft. Identity.Web은 ASP.NET Core 로깅 인프라와 통합됩니다. 다음의 여러 분야에서 문제를 진단하는 데 사용합니다.

  • 인증 흐름 - 로그인, 로그아웃, 토큰 유효성 검사
  • 토큰 획득 - 토큰 캐시 적중/누락, MSAL 작업
  • 다운스트림 API 호출 - HTTP 요청, API에 대한 토큰 획득
  • 오류 조건 - 예외, 유효성 검사 실패

기록된 구성 요소 이해

구성 요소 로그 소스 Purpose
Microsoft. Identity.Web 핵심 인증 논리 구성, 토큰 획득, API 호출
MSAL.NET Microsoft.Identity.Client 토큰 캐시 작업, 기관 유효성 검사
아이덴티티 모델 토큰 유효성 검사 JWT 구문 분석, 서명 유효성 검사, 클레임 추출
ASP.NET Core 인증 Microsoft.AspNetCore.Authentication 쿠키 작업, 차단/금지된 동작

로깅 시작

최소 구성

ID 로깅을 사용하도록 설정하려면 appsettings.json 다음 로그 수준 항목을 추가합니다.

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

이렇게 하면 Microsoft.Identity.Web 및 해당 종속성(MSAL.NET, IdentityModel)에 대한 Information-level 로깅이 가능합니다.

개발 구성

개발 중에 자세한 진단을 위해:

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

프로덕션 구성

프로덕션의 경우 오류를 캡처하는 동안 로그 볼륨을 최소화합니다.

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

로그 필터링 구성

네임스페이스 기반 필터링

네임스페이스별 로그 상세 수준을 조절합니다. 다음 구성은 각 ID 관련 네임스페이스에 대해 세분화된 수준을 설정합니다.

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

특정 로깅 사용 안 함

다른 구성 요소에 영향을 주지 않고 시끄러운 구성 요소를 음소거하려면 로그 수준을 None 또는 Warning으로 설정합니다.

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

환경별 구성

환경별 설정에 사용 appsettings.{Environment}.json :

appsettings.Development.json:

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

appsettings.Production.json:

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

로그 수준 이해

ASP.NET Core 다음 로그 수준을 정의합니다. 환경의 로그 볼륨과 진단 세부 정보 균형을 맞추는 수준을 선택합니다.

ASP.NET Core 로그 수준

수준 사용법 음량 생산?
흔적 가장 자세한 모든 작업 매우 높음 No
디버그 개발자에게 유용한 자세한 흐름 높음 No
정보 일반 흐름, 키 이벤트 보통 선택적
경고 예기치 않았지만 처리된 조건 Low
오류 오류 및 예외 매우 낮음
중요 복구할 수 없는 오류 매우 낮음
없음 로깅 사용 안 함 없음 선택적

MSAL.NET ASP.NET Core 수준에 매핑

MSAL.NET 수준 대응하는 ASP.NET Core 설명
Verbose Debug 또는 Trace 가장 자세한 메시지
Info Information 주요 인증 이벤트
Warning Warning 비정상적이지만 처리된 조건
Error Error 또는 Critical 오류 및 예외

환경별로 다음 구성을 사용합니다.

개발:

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

준비:

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

생산:

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

개인 식별 정보(PII) 로깅 구성

기본적으로 Microsoft. Identity.Web은 로그에서 PII(개인 식별 정보)를 수정합니다. 전체 사용자 세부 정보를 보려면 개발 환경에서만 PII 로깅을 사용하도록 설정합니다.

PII란?

PII(개인 식별 정보) 에는 다음이 포함됩니다.

  • 사용자 이름, 전자 메일 주소
  • 표시 이름
  • 개체 ID, 테넌트 ID
  • IP 주소
  • 토큰 값, 클레임

보안 경고

경고: 귀하와 귀하의 애플리케이션은 GDPR에서 정한 것을 포함하여 적용 가능한 모든 규제 요구 사항을 준수할 책임이 있습니다. PII 로깅을 사용하도록 설정하기 전에 이 매우 중요한 데이터를 안전하게 처리할 수 있는지 확인합니다.

PII 로깅 사용(개발 전용)

개발 구성 파일에서 EnablePiiLoggingtrue로 설정합니다.

appsettings.Development.json:

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

프로그래밍 방식으로 PII 로깅 제어

호스팅 환경에 따라 PII 로깅을 설정/해제합니다.

var builder = WebApplication.CreateBuilder(args);

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

PII를 사용하도록 설정하면 어떤 변경 내용이 있나요?

PII 로깅이 없는 경우:

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

PII를 사용하도록 설정한 경우:

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

로그의 PII 삭제

PII 로깅을 사용하지 않도록 설정하면 중요한 데이터가 다음으로 대체됩니다.

  • {hidden} - 사용자 식별자 숨기기
  • {hash:XXXX} - 실제 값 대신 해시 표시
  • *** - 토큰을 모호하게 합니다.

상관 관계 ID 사용

상관 관계 ID는 서비스 간에 인증 요청을 추적합니다. 문제 해결 속도를 높이기 위해 로그 및 지원 티켓에 포함합니다.

상관 관계 ID란?

상관 관계 ID는 인증 또는 토큰 획득 요청을 고유하게 식별하는 GUID 입니다.

  • 당신의 애플리케이션
  • Microsoft ID 플랫폼
  • MSAL.NET 라이브러리
  • Microsoft 백엔드 서비스

상관 관계 ID 가져오기

방법 1: AuthenticationResult에서

토큰 획득에 성공한 후 상관 관계 ID AuthenticationResult 를 추출합니다.

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

메서드 2: MsalServiceException에서

토큰 획득에 실패한 시점의 MsalServiceException 상관 관계 ID를 캡처합니다.

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

방법 3: 사용자 지정 상관 관계 ID 설정

사용자 지정 상관 관계 ID를 할당하여 애플리케이션 추적을 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);
}

지원을 위한 상관 관계 ID 제공

Microsoft 지원에 문의하는 경우 다음 세부 정보를 제공합니다.

  1. Correlation ID - 로그 또는 예외에서 추출한
  2. 타임스탬프 - 오류가 발생한 경우(UTC)
  3. 테넌트 ID - Microsoft Entra ID 테넌트
  4. 오류 코드 - 해당하는 경우(예: AADSTS50058)

지원 요청 예제:

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

토큰 캐시 로깅 활성화

토큰 캐시 로깅을 사용하면 캐시 적중/누락 동작을 이해하고 분산 캐시의 성능 문제를 진단할 수 있습니다.

토큰 캐시 진단 사용

분산 토큰 캐시를 사용하는 .NET Framework 또는 .NET Core 앱의 경우 자세한 로깅을 구성합니다.

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

토큰 캐시 로그 예제

캐시 히트:

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

캐시 누락:

[Debug] Token cache: No token found in cache for scopes 'user.read'
[Information] Token source: IdentityProvider
[Debug] Token cache: Token stored in 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:

로깅을 사용하여 SQL Server 분산 캐시를 구성합니다.

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

일반적인 문제 해결

다음 시나리오를 사용하여 빈번한 인증 및 권한 부여 문제를 진단합니다.

일반적인 로깅 시나리오

시나리오 1: 토큰 유효성 검사 실패

증상: 401 권한 없는 응답

자세한 로깅 사용:

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

살펴볼 항목:

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

시나리오 2: 토큰 획득 실패

증상:MsalServiceException 또는 MsalUiRequiredException

자세한 로깅 사용:

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

살펴볼 항목:

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

시나리오 3: 다운스트림 API 호출 실패

증상: 다운스트림 API를 호출하는 HTTP 502 또는 시간 제한 오류

자세한 로깅 사용:

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

컨트롤러에 사용자 지정 로깅을 추가하여 다운스트림 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");
    }
}

로그 패턴 해석

다음 예제에서는 일반적인 인증 이벤트에 대한 일반적인 로그 출력을 보여 줍니다.

성공적인 인증 흐름:

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

동의 필요:

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

토큰 새로 고침:

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

외부 공급자를 사용하여 로그 집계

모니터링 및 경고를 위해 중앙 집중식 로깅 플랫폼에 ID 로그를 전달합니다.

Application Insights 통합:

"상관 관계 ID 강화를 사용하여 Application Insights에 식별 원격 분석을 보냅니다."

using Microsoft.ApplicationInsights.Extensibility;

builder.Services.AddApplicationInsightsTelemetry();

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

Serilog 통합:

콘솔에 ID 로그를 캡처하고 파일 출력을 롤링하도록 Serilog를 구성합니다.

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

로깅 모범 사례 따르기

이러한 방법을 적용하여 ID 로그를 안전하고 유용하며 성능이 우수하게 유지합니다.

해야 할 일

1. 구조적 로깅 사용:

로그 집계자가 인덱싱하고 쿼리할 수 있도록 값을 명명된 매개 변수로 전달합니다.

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

2. 로그 상관 관계 ID:

지원 조사를 간소화하기 위해 항상 오류 로그에 상관 관계 ID를 포함합니다.

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

3. 적절한 로그 수준을 사용합니다.

로그 수준을 심각도 및 대상 그룹과 일치합니다.

_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. 프로덕션 환경에서 로그를 정리합니다.

중요한 값을 프로덕션 로그에 쓰기 전에 마스킹합니다.

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

하지 말아야 할 것들

1. 프로덕션 환경에서 PII를 사용하도록 설정하지 마세요.

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

//  Correct
"EnablePiiLogging": false

2. 비밀을 기록하지 마세요.

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

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

3. 프로덕션 환경에서 자세한 정보 로깅을 사용하지 마세요.

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

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