Passen Sie die Authentifizierung mit Microsoft an. Identity.Web

Microsoft. Identity.Web bietet sichere Standardeinstellungen für die Authentifizierung und Autorisierung in ASP.NET Core Anwendungen, die in Microsoft Entra ID integriert werden. Sie können viele Aspekte des Authentifizierungsverhaltens anpassen und gleichzeitig die integrierten Sicherheitsfeatures der Bibliothek beibehalten.

Identifizieren anpassbarer Bereiche

Fläche Anpassungsoptionen
Konfiguration Alle MicrosoftIdentityOptions, OpenIdConnectOptions, JwtBearerOptions Eigenschaften
Ereignisse OpenID Connect-Ereignisse (OnTokenValidated, OnRedirectToIdentityProviderusw.)
Tokenerwerb Korrelations-IDs, zusätzliche Abfrageparameter
Ansprüche Hinzufügen von benutzerdefinierten Ansprüchen zu ClaimsPrincipal
UI Abmeldeseiten, Umleitungsverhalten
Anmelden Anmeldehinweise, Domänenhinweise

Auswählen einer Anpassungsmethode

In der folgenden Tabelle sind die Bereiche zusammengefasst, die Sie anpassen können und welche Bereiche von den einzelnen Bereichen unterstützt werden.

Verwenden Sie eine von zwei Ansätzen zum Anpassen von Optionen:

  1. Configure<TOptions> – Konfiguriert Optionen, bevor sie verwendet werden
  2. PostConfigure<TOptions> – Konfiguriert Optionen nach allen Configure Anrufen

Reihenfolge der Ausführung:

Configure → Configure → ... → PostConfigure → PostConfigure → ... → Options used

Konfigurieren von Authentifizierungsoptionen

In diesem Abschnitt wird gezeigt, wie Sie die verschiedenen Authentifizierungsoptionsklassen konfigurieren, die Microsoft. Identity.Web verwendet.

Konfigurationszuordnung verstehen

Der "AzureAd" Abschnitt in appsettings.json wird auf mehrere Klassen abgebildet.

Sie können eine beliebige Eigenschaft aus diesen Klassen in Ihrer Konfiguration verwenden.

Muster 1: Konfigurieren von MicrosoftIdentityOptions

Der folgende Code konfiguriert MicrosoftIdentityOptions zur Aktivierung der PII-Protokollierung, um Clientfähigkeiten festzulegen und Tokenvalidierungsparameter anzupassen.

using Microsoft.Identity.Web;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));

// Customize Microsoft Identity options
builder.Services.Configure<MicrosoftIdentityOptions>(options =>
{
    // Enable PII logging (development only!)
    options.EnablePiiLogging = true;

    // Custom client capabilities
    options.ClientCapabilities = new[] { "CP1", "CP2" };

    // Override token validation parameters
    options.TokenValidationParameters.ValidateLifetime = true;
    options.TokenValidationParameters.ClockSkew = TimeSpan.FromMinutes(5);
});

var app = builder.Build();

Muster 2: Konfigurieren von OpenIdConnectOptions (Web-Apps)

Der folgende Code passt OpenIdConnectOptions für eine Web-App an, um den Antworttyp festzulegen, Cookie- und Tokenvalidierungseinstellungen zu konfigurieren und Scopes hinzuzufügen.

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));

// Customize OpenIdConnect options
builder.Services.Configure<OpenIdConnectOptions>(
    OpenIdConnectDefaults.AuthenticationScheme,
    options =>
{
    // Override response type
    options.ResponseType = "code id_token";

    // Add extra scopes
    options.Scope.Add("offline_access");
    options.Scope.Add("profile");

    // Customize token validation
    options.TokenValidationParameters.NameClaimType = "preferred_username";
    options.TokenValidationParameters.RoleClaimType = "roles";

    // Set redirect URI
    options.CallbackPath = "/signin-oidc";

    // Configure cookie options
    options.Cookie.HttpOnly = true;
    options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
    options.Cookie.SameSite = SameSiteMode.Lax;
});

Muster 3: Konfigurieren von JwtBearerOptions (Web-APIs)

Der folgende Code passt sich JwtBearerOptions für eine Web-API an, um gültige Zielgruppen, Anspruchszuordnungen und Tokenlebensdauerüberprüfung festzulegen:

using Microsoft.AspNetCore.Authentication.JwtBearer;

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));

// Customize JWT Bearer options
builder.Services.Configure<JwtBearerOptions>(
    JwtBearerDefaults.AuthenticationScheme,
    options =>
{
    // Customize audience validation
    options.TokenValidationParameters.ValidAudiences = new[]
    {
        "api://your-api-client-id",
        "https://your-api.com"
    };

    // Set custom claim mappings
    options.TokenValidationParameters.NameClaimType = "name";
    options.TokenValidationParameters.RoleClaimType = "roles";

    // Customize token validation
    options.TokenValidationParameters.ValidateLifetime = true;
    options.TokenValidationParameters.ClockSkew = TimeSpan.Zero; // No tolerance
});

Der folgende Code konfiguriert die Cookierichtlinie und cookieauthentifizierungsoptionen für Ihre App, einschließlich Sicherheitseinstellungen und Ablaufverhalten:

using Microsoft.AspNetCore.Authentication.Cookies;

// Configure cookie policy
builder.Services.Configure<CookiePolicyOptions>(options =>
{
    options.MinimumSameSitePolicy = SameSiteMode.Lax;
    options.Secure = CookieSecurePolicy.Always;
    options.HttpOnly = Microsoft.AspNetCore.CookiePolicy.HttpOnlyPolicy.Always;
});

// Configure cookie authentication options
builder.Services.Configure<CookieAuthenticationOptions>(
    CookieAuthenticationDefaults.AuthenticationScheme,
    options =>
{
    options.Cookie.Name = "MyApp.Auth";
    options.Cookie.HttpOnly = true;
    options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
    options.Cookie.SameSite = SameSiteMode.Lax;
    options.ExpireTimeSpan = TimeSpan.FromHours(1);
    options.SlidingExpiration = true;
});

Anpassen von Ereignishandlern

Die OpenID Connect- und JWT Bearer-Authentifizierung machen Ereignisse verfügbar, mit denen Sie eine Verbindung herstellen können. Microsoft. Identity.Web richtet eigene Ereignishandler ein, sodass Sie Ihre benutzerdefinierten Handler mit den vorhandenen Handlern verketten müssen, um integrierte Funktionen beizubehalten.

Beibehalten der vorhandenen Handler

Wenn Sie benutzerdefinierte Ereignishandler hinzufügen, speichern und rufen Sie zuerst den vorhandenen Handler auf. Das folgende Beispiel zeigt die falschen und korrekten Ansätze.

Der folgende Code fälschlicherweise überschreibt den Microsoft.Identity.Web-Handler.

services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options =>
{
    options.Events.OnTokenValidated = async context =>
    {
        // Your code - but you LOST the built-in validation!
        await Task.CompletedTask;
    };
});

Der folgende Code wird ordnungsgemäß mit dem vorhandenen Handler verkettet:

services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options =>
{
    var existingOnTokenValidatedHandler = options.Events.OnTokenValidated;

    options.Events.OnTokenValidated = async context =>
    {
        // Call Microsoft.Identity.Web's handler FIRST
        await existingOnTokenValidatedHandler(context);

        // Then your custom code
        // (executes AFTER built-in security checks)
        var identity = context.Principal.Identity as ClaimsIdentity;
        identity?.AddClaim(new Claim("custom_claim", "custom_value"));
    };
});

Anwenden allgemeiner Ereignisszenarien

Hinzufügen von benutzerdefinierten Ansprüchen nach der Tokenüberprüfung

Der folgende Code fügt der ClaimsPrincipal nach der Token-Überprüfung in einer Web-API benutzerdefinierte Ansprüche hinzu. Sie sucht die Abteilung des Benutzers aus einer Datenbank und weist eine anwendungsspezifische Rolle basierend auf der E-Mail-Domäne zu:

using Microsoft.AspNetCore.Authentication.JwtBearer;
using System.Security.Claims;

builder.Services.Configure<JwtBearerOptions>(
    JwtBearerDefaults.AuthenticationScheme,
    options =>
{
    var existingHandler = options.Events.OnTokenValidated;

    options.Events.OnTokenValidated = async context =>
    {
        // Preserve built-in validation
        await existingHandler(context);

        // Add custom claims
        var identity = context.Principal.Identity as ClaimsIdentity;

        // Example: Add department claim from database
        var userObjectId = context.Principal.FindFirst("oid")?.Value;
        if (!string.IsNullOrEmpty(userObjectId))
        {
            var department = await GetUserDepartment(userObjectId);
            identity?.AddClaim(new Claim("department", department));
        }

        // Example: Add application-specific role
        var email = context.Principal.FindFirst("email")?.Value;
        if (email?.EndsWith("@admin.com") == true)
        {
            identity?.AddClaim(new Claim(ClaimTypes.Role, "SuperAdmin"));
        }
    };
});

Der folgende Code fügt benutzerdefinierte Ansprüche in einer Web-App hinzu, indem Microsoft Graph aufgerufen wird, um zusätzliche Benutzerprofildaten nach der Tokenüberprüfung abzurufen:

using Microsoft.AspNetCore.Authentication.OpenIdConnect;

builder.Services.Configure<OpenIdConnectOptions>(
    OpenIdConnectDefaults.AuthenticationScheme,
    options =>
{
    var existingHandler = options.Events.OnTokenValidated;

    options.Events.OnTokenValidated = async context =>
    {
        // Preserve built-in processing
        await existingHandler(context);

        // Call Microsoft Graph to get additional user data
        var graphClient = context.HttpContext.RequestServices
            .GetRequiredService<GraphServiceClient>();

        var user = await graphClient.Me.GetAsync();

        var identity = context.Principal.Identity as ClaimsIdentity;
        identity?.AddClaim(new Claim("jobTitle", user?.JobTitle ?? ""));
        identity?.AddClaim(new Claim("department", user?.Department ?? ""));
    };
});

Hinzufügen von Abfrageparametern zur Autorisierungsanforderung

Der folgende Code fügt der Autorisierungsanforderung, die an den identitätsanbieter Microsoft Entra gesendet wird, benutzerdefinierte Abfrageparameter hinzu:

builder.Services.Configure<OpenIdConnectOptions>(
    OpenIdConnectDefaults.AuthenticationScheme,
    options =>
{
    var existingHandler = options.Events.OnRedirectToIdentityProvider;

    options.Events.OnRedirectToIdentityProvider = async context =>
    {
        // Preserve existing behavior
        if (existingHandler != null)
        {
            await existingHandler(context);
        }

        // Add custom query parameters
        context.ProtocolMessage.Parameters.Add("slice", "testslice");
        context.ProtocolMessage.Parameters.Add("custom_param", "custom_value");

        // Conditional parameters based on request
        if (context.HttpContext.Request.Query.ContainsKey("prompt"))
        {
            context.ProtocolMessage.Prompt = context.HttpContext.Request.Query["prompt"];
        }
    };
});

Anpassen der Behandlung von Authentifizierungsfehlern

Der folgende Code behandelt Authentifizierungsfehler, indem der Fehler protokolliert und eine benutzerdefinierte JSON-Fehlerantwort zurückgegeben wird:

builder.Services.Configure<OpenIdConnectOptions>(
    OpenIdConnectDefaults.AuthenticationScheme,
    options =>
{
    options.Events.OnAuthenticationFailed = async context =>
    {
        // Log the error
        var logger = context.HttpContext.RequestServices
            .GetRequiredService<ILogger<Program>>();
        logger.LogError(context.Exception, "Authentication failed");

        // Customize error response
        context.Response.StatusCode = 401;
        context.Response.ContentType = "application/json";
        await context.Response.WriteAsync($$"""
            {
                "error": "authentication_failed",
                "error_description": "{{context.Exception.Message}}"
            }
            """);

        context.HandleResponse(); // Suppress default error handling
    };
});

Behandeln des verweigerten Zugriffs

Der folgende Code leitet Benutzer zu einer benutzerdefinierten Seite um, wenn sie die Zustimmung verweigern:

builder.Services.Configure<OpenIdConnectOptions>(
    OpenIdConnectDefaults.AuthenticationScheme,
    options =>
{
    options.Events.OnAccessDenied = async context =>
    {
        // User denied consent
        context.Response.Redirect("/Home/AccessDenied");
        context.HandleResponse();
        await Task.CompletedTask;
    };
});

Tokenerwerb anpassen

Sie können anpassen, wie Token beim Aufrufen von downstream-APIs erworben werden, indem Sie Optionen übergeben.IDownstreamApi

Verwenden von IDownstreamApi mit benutzerdefinierten Optionen

Der folgende Code übergibt beim Abrufen eines Tokens durch IDownstreamApi eine Korrelations-ID und zusätzliche Abfrageparameter:

using Microsoft.Identity.Abstractions;

public class TodoListController : ControllerBase
{
    private readonly IDownstreamApi _downstreamApi;

    public TodoListController(IDownstreamApi downstreamApi)
    {
        _downstreamApi = downstreamApi;
    }

    [HttpGet("{id}")]
    public async Task<ActionResult> GetTodo(int id, Guid correlationId)
    {
        var result = await _downstreamApi.GetForUserAsync<Todo>(
            "TodoListService",
            options =>
            {
                options.RelativePath = $"api/todolist/{id}";

                // Customize token acquisition
                options.TokenAcquisitionOptions = new TokenAcquisitionOptions
                {
                    CorrelationId = correlationId,
                    ExtraQueryParameters = new Dictionary<string, string>
                    {
                        { "slice", "test_slice" }
                    }
                };
            });

        return Ok(result);
    }
}

Anpassen der Benutzeroberfläche

Sie können steuern, wo Benutzer nach der Anmeldung und Abmeldung landen, und die Abmeldeerfahrung anpassen.

Umleiten zu einer bestimmten Seite nach der Anmeldung

Verwenden Sie den redirectUri Parameter, um Benutzer nach der Anmeldung an eine bestimmte Seite zu senden:

<!-- Razor view -->
<a href="/MicrosoftIdentity/Account/SignIn?redirectUri=/Dashboard">Sign In</a>

<!-- Or in controller -->
[HttpGet]
public IActionResult SignInToDashboard()
{
    return RedirectToAction("SignIn", "Account", new
    {
        area = "MicrosoftIdentity",
        redirectUri = "/Dashboard"
    });
}

Abmeldeseite anpassen

Option 1: Überschreiben der Razor-Seite

Erstellen Sie eine Datei bei Areas/MicrosoftIdentity/Pages/Account/SignedOut.cshtml mit Ihren benutzerdefinierten Inhalten.

@page
@model Microsoft.Identity.Web.UI.Areas.MicrosoftIdentity.Pages.Account.SignedOutModel
@{
    ViewData["Title"] = "Signed out";
}

<div class="container text-center mt-5">
    <h1>You have been signed out</h1>
    <p>Thank you for using our application.</p>
    <a asp-area="" asp-controller="Home" asp-action="Index" class="btn btn-primary">
        Return to Home
    </a>
</div>

Option 2: Umleiten zu einer benutzerdefinierten Seite

Mit dem folgenden Code werden Benutzer anstelle der Standardeinstellung auf eine benutzerdefinierte abgemeldete Seite umgeleitet:

builder.Services.Configure<OpenIdConnectOptions>(
    OpenIdConnectDefaults.AuthenticationScheme,
    options =>
{
    options.Events.OnSignedOutCallbackRedirect = context =>
    {
        context.Response.Redirect("/Home/SignedOut");
        context.HandleResponse();
        return Task.CompletedTask;
    };
});

Anpassung des Anmeldeerlebnisses

Verwenden von Anmeldehinweisen und Domänenhinweisen

Optimieren Sie die Anmeldeumgebung, indem Sie Benutzernamen vorab auffüllen und Benutzer an bestimmte Microsoft Entra Mandanten weiterleiten.

Hinweise verstehen

Hint Purpose Beispiel
loginHint Vorausfüllen des Benutzernamen-/E-Mail-Felds "user@contoso.com"
domainHint Gehe direkt zu einer bestimmten Mandanten-Login-Seite "contoso.com"

Hinweismuster anwenden

Muster 1: Controllerbasiert

Der folgende Code zeigt Controlleraktionen für standardanmeldung, Anmeldung mit Anmeldehinweisen, Domänenhinweisen oder beides:

using Microsoft.AspNetCore.Mvc;

public class AuthController : Controller
{
    [HttpGet]
    public IActionResult SignIn()
    {
        // Standard sign-in
        return RedirectToAction("SignIn", "Account", new
        {
            area = "MicrosoftIdentity",
            redirectUri = "/Dashboard"
        });
    }

    [HttpGet]
    public IActionResult SignInWithLoginHint()
    {
        // Pre-populate username
        return RedirectToAction("SignIn", "Account", new
        {
            area = "MicrosoftIdentity",
            redirectUri = "/Dashboard",
            loginHint = "user@contoso.com"
        });
    }

    [HttpGet]
    public IActionResult SignInWithDomainHint()
    {
        // Direct to Contoso tenant
        return RedirectToAction("SignIn", "Account", new
        {
            area = "MicrosoftIdentity",
            redirectUri = "/Dashboard",
            domainHint = "contoso.com"
        });
    }

    [HttpGet]
    public IActionResult SignInWithBothHints()
    {
        // Pre-populate AND direct to tenant
        return RedirectToAction("SignIn", "Account", new
        {
            area = "MicrosoftIdentity",
            redirectUri = "/Dashboard",
            loginHint = "user@contoso.com",
            domainHint = "contoso.com"
        });
    }
}

Muster 2: Ansichtsbasiert

Der folgende HTML-Code zeigt Anmeldelinks mit unterschiedlichen Hinweiskonfigurationen:

<div class="sign-in-options">
    <h2>Sign In Options</h2>

    <!-- Standard sign-in -->
    <a href="/MicrosoftIdentity/Account/SignIn?redirectUri=/Dashboard"
       class="btn btn-primary">
        Sign In
    </a>

    <!-- With login hint -->
    <a href="/MicrosoftIdentity/Account/SignIn?redirectUri=/Dashboard&loginHint=user@contoso.com"
       class="btn btn-secondary">
        Sign In as user@contoso.com
    </a>

    <!-- With domain hint -->
    <a href="/MicrosoftIdentity/Account/SignIn?redirectUri=/Dashboard&domainHint=contoso.com"
       class="btn btn-secondary">
        Sign In (Contoso)
    </a>
</div>

Muster 3: Programmgesteuert mit OnRedirectToIdentityProvider

Der folgende Code legt hinweise basierend auf Abfrageparametern und Cookies während der Umleitung zum Identitätsanbieter dynamisch fest:

builder.Services.Configure<OpenIdConnectOptions>(
    OpenIdConnectDefaults.AuthenticationScheme,
    options =>
{
    var existingHandler = options.Events.OnRedirectToIdentityProvider;

    options.Events.OnRedirectToIdentityProvider = async context =>
    {
        if (existingHandler != null)
        {
            await existingHandler(context);
        }

        // Add hints based on application logic
        if (context.HttpContext.Request.Query.TryGetValue("tenant", out var tenant))
        {
            context.ProtocolMessage.DomainHint = tenant;
        }

        // Get suggested user from cookie or session
        var suggestedUser = context.HttpContext.Request.Cookies["LastSignedInUser"];
        if (!string.IsNullOrEmpty(suggestedUser))
        {
            context.ProtocolMessage.LoginHint = suggestedUser;
        }
    };
});

Anwendungsfälle

E-Commerce-Plattform:

// Pre-fill returning customer email
loginHint = customerEmail

B2B-Anwendung:

// Direct to customer's tenant
domainHint = customerDomain

Mehrinstanzenfähige SaaS:

// Route based on subdomain
domainHint = GetTenantFromSubdomain(Request.Host)

Bewährte Methoden befolgen

Empfohlen

1. Vorhandene Ereignishandler immer beibehalten. Speichern und Aufrufen des vorhandenen Handlers vor dem Ausführen der benutzerdefinierten Logik:

var existingHandler = options.Events.OnTokenValidated;
options.Events.OnTokenValidated = async context =>
{
    await existingHandler(context); // Call Microsoft.Identity.Web's handler
    // Your custom code
};

2. Verwenden Sie Korrelations-IDs für die Ablaufverfolgung. Anfügen einer Korrelations-ID an Tokenakquisitionsanforderungen für die Diagnose:

var tokenOptions = new TokenAcquisitionOptions
{
    CorrelationId = Activity.Current?.Id ?? Guid.NewGuid()
};

3. Überprüfen sie benutzerdefinierte Ansprüche. Stellen Sie sicher, dass benutzerdefinierte Ansprüche erwartete Werte enthalten, bevor Sie Zugriff gewähren:

var department = context.Principal.FindFirst("department")?.Value;
if (!IsValidDepartment(department))
{
    throw new UnauthorizedAccessException("Invalid department");
}

4. Protokollieren von Anpassungsfehlern. Umschließen Sie benutzerdefinierte Logik in "try-catch"-Blöcken und protokollieren Sie Fehler.

try
{
    // Custom logic
}
catch (Exception ex)
{
    logger.LogError(ex, "Custom authentication logic failed");
    throw;
}

5. Testen Sie sowohl Erfolgs- als auch Fehlerpfade. Behandeln Sie alle Authentifizierungsszenarien in Ihren Tests:

// Test with valid tokens
// Test with missing claims
// Test with expired tokens
// Test with wrong audience

DONT‘s

1. Überspringen Sie die Ereignishandler von Microsoft.Identity.Web nicht:

//  Wrong - loses built-in security checks
options.Events.OnTokenValidated = async context => { /* your code */ };

//  Correct - preserves security
var existing = options.Events.OnTokenValidated;
options.Events.OnTokenValidated = async context =>
{
    await existing(context);
    /* your code */
};

2. Aktivieren Sie keine PII-Protokollierung in der Produktion:

//  Wrong
options.EnablePiiLogging = true; // In production!

//  Correct
if (builder.Environment.IsDevelopment())
{
    options.EnablePiiLogging = true;
}

3. Umgehen Sie die Tokenüberprüfung nicht:

//  Wrong - insecure!
options.TokenValidationParameters.ValidateLifetime = false;
options.TokenValidationParameters.ValidateAudience = false;

//  Correct - maintain security
options.TokenValidationParameters.ValidateLifetime = true;
options.TokenValidationParameters.ClockSkew = TimeSpan.FromMinutes(5);

4. Hartcodieren Sie keine vertraulichen Werte:

//  Wrong
options.ClientSecret = "mysecret123";

//  Correct
options.ClientSecret = builder.Configuration["AzureAd:ClientSecret"];

5. Ändern Sie die Authentifizierung in Middleware nicht:

//  Wrong - configure in Startup, not middleware
app.Use(async (context, next) =>
{
    // Modifying auth options here is too late!
});

Häufige Probleme beheben

Anpassung nicht wirksam

Ausführungsreihenfolge überprüfen:

  1. AddMicrosoftIdentityWebApp / AddMicrosoftIdentityWebApi legt Standardwerte fest.
  2. Ihre Configure Anrufe werden ausgeführt
  3. PostConfigure Aufrufe werden ausgeführt (falls vorhanden)
  4. Optionen werden verwendet.

Lösung: Verwenden Sie PostConfigure , wenn Ihr Configure Anruf nicht wirksam wird, da PostConfigure er nach allen Configure Anrufen ausgeführt wird:

services.PostConfigure<OpenIdConnectOptions>(
    OpenIdConnectDefaults.AuthenticationScheme,
    options => { /* your changes */ }
);

Beheben fehlender benutzerdefinierter Ansprüche

Überprüfen Sie Folgendes, wenn keine benutzerdefinierten Ansprüche angezeigt werden:

  1. Der OnTokenValidated Handler wird korrekt mit dem vorhandenen Handler verkettet.
  2. Die Authentifizierung ist erfolgreich, bevor Ihr Code Ansprüche hinzufügt.
  3. Ansprüche werden dem richtigen ClaimsIdentityhinzugefügt.

Der folgende Code protokolliert alle Ansprüche für das Debuggen:

var claims = context.Principal.Claims.ToList();
logger.LogInformation($"Claims count: {claims.Count}");
foreach (var claim in claims)
{
    logger.LogInformation($"{claim.Type}: {claim.Value}");
}

Beheben von Ereignissen, die nicht ausgelöst werden

Wenn Ereignisse nicht ausgelöst werden, überprüfen Sie, ob die Authentifizierungs- und Autorisierungs-Middleware in der richtigen Reihenfolge registriert sind:

app.UseAuthentication(); // Must be first
app.UseAuthorization();  // Must be second
app.MapControllers();    // Then endpoints