Tokencache in Microsoft. Identity.Web

Die Zwischenspeicherung von Token verbessert die Anwendungsleistung, Zuverlässigkeit und Benutzerfreundlichkeit. Microsoft. Identity.Web bietet flexible Caching-Strategien, die Leistung, Persistenz und Betriebssicherheit ausgleichen.

Übersicht

In diesem Abschnitt wird beschrieben, welche Token Microsoft.Identity.Web zwischenspeichert und warum Caching für Ihre Anwendung wichtig ist.

Welche Token werden zwischengespeichert?

Microsoft.Identity.Web speichert mehrere Tokentypen zwischen:

Tokentyp Größe Geltungsbereich Räumung
Zugriffstoken ~2 KB Pro (Benutzer/App, Mandant, Ressource) Automatisch (lebensdauerbasiert)
Aktualisierungstoken Variable Pro Benutzerkonto Manuell oder richtlinienbasiert
ID-Token ~2-7 KB Pro Benutzer Automatisch

Dabei gilt die Tokenzwischenspeicherung:

Warum Cachetoken?

Leistungsvorteile:

  • Reduziert Roundtrips zu Microsoft Entra ID.
  • Schnellere API-Aufrufe (L1: <10 ms vs L2: ~30 ms vs Netzwerk: >100 ms)
  • Geringere Latenz für Endbenutzer

Zuverlässigkeitsvorteile:

  • Setzt die Arbeit während temporärer Microsoft Entra Ausfälle fort
  • Widerstandsfähig gegen Netzwerkanomalien
  • Reibungslose Verschlechterung, wenn der verteilte Cache fehlschlägt

Kostenvorteile:

  • Reduziert Authentifizierungsanforderungen (Drosselungsvermeidung)
  • Niedrigere Azure Kosten für Authentifizierungsvorgänge

Schnellstart

Beginnen Sie schnell mit einer der folgenden Cachekonfigurationen, je nach Ihrer Umgebung.

Entwicklung – Speichercache

Im folgenden Beispiel wird ein Speichertokencache hinzugefügt, der für die Entwicklung und Beispiele geeignet ist:

using Microsoft.Identity.Web;

builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, "AzureAd")
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddInMemoryTokenCaches();

Vorteile:

  • Einfache Einrichtung
  • Schnelle Leistung
  • Keine externen Abhängigkeiten

Nachteile:

  • Cache beim Neustart der App verloren gegangen. In einer Web-App bleiben Benutzer über das Cookie angemeldet, müssen sich aber erneut anmelden, um ein Zugriffstoken zu erhalten und den Cache erneut zu füllen.
  • Für Produktionsbereitstellungen mit mehreren Servern nicht geeignet
  • Nicht zwischen Anwendungsinstanzen geteilt

Produktion – verteilter Cache

Verwenden Sie für Produktionsanwendungen, insbesondere für Bereitstellungen mit mehreren Servern, einen verteilten Cache, der von Redis oder einem anderen Anbieter unterstützt wird:

using Microsoft.Identity.Web;

builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, "AzureAd")
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDistributedTokenCaches();

// Choose your cache implementation
builder.Services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = builder.Configuration.GetConnectionString("Redis");
    options.InstanceName = "MyApp_";
});

Vorteile:

  • Überdauert App-Neustarts
  • Für alle Anwendungsinstanzen freigegeben
  • Automatisches Caching von L1+L2

Nachteile:

  • Erfordert externe Cacheinfrastruktur
  • Zusätzliche Konfigurationskomplexität
  • Netzwerklatenz für Cachevorgänge

Auswählen einer Cachestrategie

Verwenden Sie das folgende Entscheidungsflussdiagramm und die folgende Matrix, um die Cachestrategie auszuwählen, die am besten zu Ihrer Bereitstellung passt.

flowchart TD
    Start([Token Caching<br/>Decision]) --> Q1{Production<br/>Environment?}

    Q1 -->|No - Dev/Test| DevChoice[In-Memory Cache<br/>AddInMemoryTokenCaches]
    Q1 -->|Yes| Q2{Multiple Server<br/>Instances?}

    Q2 -->|No - Single Server| Q3{App Restarts<br/>Acceptable?}
    Q3 -->|Yes| DevChoice
    Q3 -->|No| DistChoice

    Q2 -->|Yes| DistChoice[Distributed Cache<br/>AddDistributedTokenCaches]

    DistChoice --> Q4{Cache<br/>Implementation?}

    Q4 -->|High Performance| Redis[Redis Cache<br/>StackExchange.Redis<br/>⭐ Recommended]
    Q4 -->|Azure Native| Azure[Azure Cache for Redis,<br/>Azure Cosmos DB,<br/>or Azure Database for PostgreSQL]
    Q4 -->|On-Premises| SQL[SQL Server Cache<br/>AddDistributedSqlServerCache]
    Q4 -->|Testing| DistMem[Distributed Memory<br/>Not for production]

    Redis --> L1L2[Automatic L1+L2<br/>Caching]
    Azure --> L1L2
    SQL --> L1L2
    DistMem --> L1L2

    L1L2 --> Config[Configure Options<br/>MsalDistributedTokenCacheAdapterOptions]
    DevChoice --> MemConfig[Configure Memory Options<br/>MsalMemoryTokenCacheOptions]

    style Start fill:#e1f5ff
    style DevChoice fill:#d4edda
    style DistChoice fill:#fff3cd
    style Redis fill:#d1ecf1
    style L1L2 fill:#f8d7da

Entscheidungsmatrix

In der folgenden Tabelle werden die empfohlenen Cachetypen für allgemeine Bereitstellungsszenarien zusammengefasst.

Szenario Empfohlener Cache Begründung
Lokale Entwicklung In-Memory Einfachheit, keine Infrastruktur erforderlich
Beispiele/Demos In-Memory Einfache Einrichtung für Demonstrationen
Einzelserverbetrieb (Neustarts in Ordnung) In-Memory Akzeptabel, wenn Sitzungen neu eingerichtet werden können
Produktion mit mehreren Servern Redis Freigegebener Cache, hohe Leistung, zuverlässig
Azure gehostete Anwendungen Azure Cache for Redis Native Azure Integration, verwalteter Dienst
Lokales Unternehmen SQL Server Nutzt vorhandene Infrastruktur
PostgreSQL-Umgebungen PostgreSQL Verwendet vorhandene PostgreSQL-Datenbank, vertraute SQL-Semantik
Hochsicherheitsumgebungen SQL Server + Verschlüsselung Datenresidenz, Verschlüsselung ruhender Daten
Testen verteilter Szenarien Verteilter Speicher Testet das L2-Cacheverhalten ohne Infrastruktur

Cacheimplementierungen

Microsoft. Identity.Web unterstützt mehrere Cacheimplementierungen. Wählen Sie die Option aus, die Ihren Infrastruktur- und Verfügbarkeitsanforderungen entspricht.

In-Memory-Cache

Verwendungsbedingungen:

  • Entwickeln und Testen
  • Bereitstellungen mit einem einzelnen Server mit akzeptablem Neustartverhalten
  • Beispiele und Prototypen

Configuration:

Der folgende Code registriert den Speichertoken-Cache im Speicher mit Standardeinstellungen.

builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, "AzureAd")
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddInMemoryTokenCaches();

Mit benutzerdefinierten Optionen:

Sie können Ablaufdatum und Größenbeschränkungen anpassen, indem Sie Optionen angeben.

builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, "AzureAd")
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddInMemoryTokenCaches(options =>
    {
        // Token cache entry will expire after this duration
        options.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1);

        // Limit cache size (default is unlimited)
        options.SizeLimit = 500 * 1024 * 1024; // 500 MB
    });

→ Weitere Informationen zur Konfiguration des Speichercaches


Verteilter Cache (L2) mit automatischer L1-Unterstützung

Verwendungsbedingungen:

  • Implementierungen in Produktionsumgebungen mit mehreren Servern
  • Anwendungen, die eine Cachepersistenz über Neustarts erfordern
  • Hochverfügbarkeitsszenarien

Hauptmerkmal: Seit Microsoft.Identity.Web v1.8.0 enthält der verteilte Cache automatisch einen L1-Cache im Arbeitsspeicher für Leistung und Zuverlässigkeit.

Fügen Sie die Redis-Verbindungszeichenfolge zu appsettings.json hinzu:

{
  "ConnectionStrings": {
    "Redis": "localhost:6379"
  }
}

Registrieren Sie dann den verteilten Tokencache und den Redis-Anbieter in Program.cs:

using Microsoft.Identity.Web;
using Microsoft.Identity.Web.TokenCacheProviders.Distributed;

builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, "AzureAd")
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDistributedTokenCaches();

// Redis cache implementation
builder.Services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = builder.Configuration.GetConnectionString("Redis");
    options.InstanceName = "MyApp_"; // Unique prefix per application
});

// Optional: Configure distributed cache behavior
builder.Services.Configure<MsalDistributedTokenCacheAdapterOptions>(options =>
{
    // Control L1 cache size
    options.L1CacheOptions.SizeLimit = 500 * 1024 * 1024; // 500 MB

    // Handle L2 cache failures gracefully
    options.OnL2CacheFailure = (exception) =>
    {
        if (exception is StackExchange.Redis.RedisConnectionException)
        {
            // Log the failure
            // Optionally attempt reconnection
            return true; // Retry the operation
        }
        return false; // Don't retry
    };
});

Azure Cache for Redis

Um Azure Cache for Redis zu verwenden, registrieren Sie den Cache mit Ihrem Azure Verbindungszeichenfolge:

builder.Services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = builder.Configuration.GetConnectionString("AzureRedis");
    options.InstanceName = "MyApp_";
});

Format der Verbindungszeichenfolge:

<cache-name>.redis.cache.windows.net:6380,password=<access-key>,ssl=True,abortConnect=False

SQL Server-Cache

Im folgenden Beispiel wird SQL Server als verteiltes Cache-Back-End konfiguriert:

builder.Services.AddDistributedSqlServerCache(options =>
{
    options.ConnectionString = builder.Configuration.GetConnectionString("TokenCacheDb");
    options.SchemaName = "dbo";
    options.TableName = "TokenCache";

    // Set expiration longer than access token lifetime (default 1 hour)
    // This prevents cache entries from expiring before tokens
    options.DefaultSlidingExpiration = TimeSpan.FromMinutes(90);
});

Azure Cosmos DB Cache

Im folgenden Beispiel wird Azure Cosmos DB als verteiltes Cache-Back-End konfiguriert:

builder.Services.AddCosmosCache((CosmosCacheOptions options) =>
{
    options.ContainerName = builder.Configuration["CosmosCache:ContainerName"];
    options.DatabaseName = builder.Configuration["CosmosCache:DatabaseName"];
    options.ClientBuilder = new CosmosClientBuilder(
        builder.Configuration["CosmosCache:ConnectionString"]);
    options.CreateIfNotExists = true;
});

PostgreSQL-Cache

Erfordert das Microsoft.Extensions.Caching.Postgres NuGet-Paket.

appsettings.json:

{
  "ConnectionStrings": {
    "PostgresCache": "Host=localhost;Database=mydb;Username=myuser;Password=mypassword"
  },
  "PostgresCache": {
    "SchemaName": "public",
    "TableName": "token_cache",
    "CreateIfNotExists": true
  }
}

Registrieren Sie dann den PostgreSQL-Cache in Program.cs:

builder.Services.AddDistributedPostgresCache(options =>
{
    options.ConnectionString = builder.Configuration.GetConnectionString("PostgresCache");
    options.SchemaName = builder.Configuration["PostgresCache:SchemaName"];
    options.TableName = builder.Configuration["PostgresCache:TableName"];
    options.CreateIfNotExists = builder.Configuration.GetValue<bool>("PostgresCache:CreateIfNotExists");
    options.DefaultSlidingExpiration = TimeSpan.FromMinutes(90);
});

→ Weitere Informationen zur Konfiguration des verteilten Caches


Vorsicht

Die sitzungsbasierte Zwischenspeicherung hat erhebliche Einschränkungen. Verwenden Sie stattdessen einen verteilten Cache.

Das folgende Beispiel zeigt die sitzungsbasierte Tokenzwischenspeicherung als Referenz:

using Microsoft.Identity.Web.TokenCacheProviders.Session;

// In Program.cs
builder.Services.AddSession();

builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, "AzureAd")
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddSessionTokenCaches();

// In middleware pipeline
app.UseSession(); // Must be before UseAuthentication()
app.UseAuthentication();
app.UseAuthorization();

Limitations:

  • Probleme mit der Cookiegröße – Große ID-Token mit vielen Ansprüchen verursachen Probleme
  • Scope-Konflikte - Kann nicht mit einem Singleton TokenAcquisition verwendet werden (z. B. Microsoft Graph SDK)
  • Sitzungsaffinität ist erforderlich – Funktioniert nicht gut in Lastenausgleichsszenarien
  • Nicht empfohlen – Stattdessen verteilten Cache verwenden

Erweiterte Konfiguration

Mit diesen Optionen können Sie das Cacheverhalten für Leistungs-, Sicherheits- und Entfernungsrichtlinien optimieren.

L1-Cache-Steuerung

Der L1-Cache (im Arbeitsspeicher) verbessert die Leistung, wenn Sie verteilte Caches verwenden. Der folgende Code konfiguriert L1-Cachegröße und -verhalten:

builder.Services.Configure<MsalDistributedTokenCacheAdapterOptions>(options =>
{
    // Control L1 cache size (default: 500 MB)
    options.L1CacheOptions.SizeLimit = 100 * 1024 * 1024; // 100 MB

    // Disable L1 cache if session affinity is not available
    // (forces all requests to use L2 cache for consistency)
    options.DisableL1Cache = false;
});

Wann L1 deaktiviert werden soll:

  • Keine Sitzungsaffinität im Load-Balancer
  • Benutzer werden häufig aufgefordert, MFA zu verwenden, aufgrund von Cache-Inkonsistenz.
  • Kompromiss: L2-Zugriff ist langsamer (~30 ms vs ~10 ms)

Cache-Entfernungsrichtlinien

Eviction-Richtlinien steuern, wann zwischengespeicherte Token entfernt werden. Der folgende Code legt die absoluten und gleitenden Ablaufzeiten fest.

builder.Services.Configure<MsalDistributedTokenCacheAdapterOptions>(options =>
{
    // Absolute expiration (removed after this time, regardless of use)
    options.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(72);

    // Sliding expiration (renewed on each access)
    options.SlidingExpiration = TimeSpan.FromHours(2);
});

Sie können die Eviction auch über appsettings.jsonkonfigurieren:

{
  "TokenCacheOptions": {
    "AbsoluteExpirationRelativeToNow": "72:00:00",
    "SlidingExpiration": "02:00:00"
  }
}
builder.Services.Configure<MsalDistributedTokenCacheAdapterOptions>(
    builder.Configuration.GetSection("TokenCacheOptions"));

Recommendations:

  • Ablaufdatum auf länger als die Lebensdauer des Tokens festlegen (Tokens laufen normalerweise nach 1 Stunde ab)
  • Standard: 90 Minuten gleitende Ablaufzeit
  • Gleichgewicht zwischen Speicherauslastung und Benutzererfahrung
  • Berücksichtigen Sie: 72 Stunden absolut + 2 Stunden flexibler Zeitraum für eine optimale Benutzerfreundlichkeit (UX).

→ Erfahren Sie mehr über Strategien zur Cacheräumung


Verschlüsselung im Ruhezustand

Um vertrauliche Tokendaten in verteilten Caches zu schützen, aktivieren Sie die Verschlüsselung über ASP.NET Core Datenschutz.

Einzelner Computer

Aktivieren Sie auf einem einzelnen Computer die Verschlüsselung mit dem integrierten Datenschutzanbieter:

builder.Services.Configure<MsalDistributedTokenCacheAdapterOptions>(options =>
{
    options.Encrypt = true; // Uses ASP.NET Core Data Protection
});

Verteilte Systeme (mehrere Server)

Von Bedeutung

Verteilte Systeme teilen standardmäßig keine Verschlüsselungsschlüssel. Sie müssen die Schlüsselfreigabe konfigurieren:

Azure Key Vault (empfohlen):

Der folgende Code speichert Schlüssel zum Azure Blob Storage und schützt sie mit Azure Key Vault:

using Microsoft.AspNetCore.DataProtection;

builder.Services.AddDataProtection()
    .PersistKeysToAzureBlobStorage(new Uri(builder.Configuration["DataProtection:BlobUri"]))
    .ProtectKeysWithAzureKeyVault(
        new Uri(builder.Configuration["DataProtection:KeyIdentifier"]),
        new DefaultAzureCredential());

Zertifikatbasiert:

Der folgende Code speichert Schlüssel für eine Dateifreigabe und schützt sie mit einem X.509-Zertifikat:

builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\keys"))
    .ProtectKeysWithCertificate(
        new X509Certificate2("current.pfx", builder.Configuration["CertPassword"]))
    .UnprotectKeysWithAnyCertificate(
        new X509Certificate2("current.pfx", builder.Configuration["CertPassword"]),
        new X509Certificate2("previous.pfx", builder.Configuration["PrevCertPassword"]));

→ Erfahren Sie mehr über Verschlüsselung und Datenschutz


Überlegungen zur Cacheleistung

Verwenden Sie die folgenden Schätzungen, um die Cachekapazität für Ihre Anwendung zu planen.

Schätzungen zur Tokengröße

Tokentyp Typische Größe Pro Hinweise
App-Token ~2 KB Mandanten-×-Ressource Automatisch entfernt
Benutzertoken ~7 KB Benutzer × Mandant × Ressource Manuelle Entfernung erforderlich
Aktualisierungstoken Variable Benutzer Langlebig

Speicherplanung

Für 500 gleichzeitige Benutzer , die 3 APIs aufrufen:

  • Benutzertoken: 500 × 3 × 7 KB = 10,5 MB
  • Mit Mehraufwand: ~15-20 MB

Für 10.000 gleichzeitige Benutzer:

  • Benutzertoken: 10.000 × 3 × 7 KB = 210 MB
  • Mit Mehraufwand: ~300-350 MB

Empfehlung: Legen Sie die Größenbeschränkung für den L1-Cache basierend auf erwarteten gleichzeitigen Benutzern fest.

Bewährte Methoden

Befolgen Sie diese Richtlinien, um einen zuverlässigen und effizienten Token-Cache sicherzustellen.

Verwenden des verteilten Caches in der Produktion – Unerlässlich für Bereitstellungen mit mehreren Servern

Festlegen geeigneter Cachegrößenbeschränkungen – Verhindern eines ungebundenen Speicherwachstums

Konfigurieren von Verdrängungsrichtlinien – Ausgewogene UX- und Speicherauslastung

Verschlüsselung für vertrauliche Daten aktivieren – Token im Ruhezustand schützen

Überwachen der Cacheintegrität – Nachverfolgen von Trefferraten, Fehlern und Leistung

Behandeln von L2-Cachefehlern ordnungsgemäß – L1-Cache sorgt für Resilienz

Testen des Cacheverhaltens – Überprüfen von Neustartszenarien und Failover

Verwenden Sie keinen verteilten Speichercache in der Produktion – nicht persistent oder verteilt

Sitzungscache nicht verwenden – Hat erhebliche Einschränkungen

Ablauf nicht kürzer als die Tokenlebensdauer festlegen – Erzwingt unnötige erneute Authentifizierung

Vergessen Sie nicht die Freigabe von Verschlüsselungsschlüsseln – Verteilte Systeme benötigen gemeinsam genutzte Schlüssel