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 로깅 사용(개발 전용)
개발 구성 파일에서 EnablePiiLogging를 true로 설정합니다.
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 지원에 문의하는 경우 다음 세부 정보를 제공합니다.
- Correlation ID - 로그 또는 예외에서 추출한
- 타임스탬프 - 오류가 발생한 경우(UTC)
- 테넌트 ID - Microsoft Entra ID 테넌트
-
오류 코드 - 해당하는 경우(예:
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"