TokenCache i Microsoft.Identity.Web

Cachelagring av token förbättrar programmets prestanda, tillförlitlighet och användarupplevelse. Microsoft. Identity.Web tillhandahåller flexibla cachelagringsstrategier som balanserar prestanda, beständighet och drifttillförlitlighet.

Översikt

I det här avsnittet beskrivs vilka tokens Microsoft.Identity.Web cachar och varför cachning är viktigt för din applikation.

Vilka token cachelagras?

Microsoft. Identity.Web cachelagrar flera typer av token:

Tokentyp Storlek Scope Vräkning
Token för åtkomst ~2 kB Per (användare/app, hyresgäst, resurs) Automatisk (livstidsbaserad)
Uppdatera token Variabel Per användarkonto Manuell eller principbaserad
ID-token ~2-7 KB Per användare Automatiskt

Där cachelagring av token gäller:

Varför cachetoken?

Prestandafördelar:

  • Minskar antal fram- och återresor till Microsoft Entra ID
  • Snabbare API-anrop (L1: <10 ms jämfört med L2: ~30 ms jämfört med nätverk: >100 ms)
  • Kortare svarstid för slutanvändare

Tillförlitlighetsfördelar:

  • Fortsätter att arbeta under tillfälliga Microsoft Entra avbrott
  • Motståndskraftig mot nätverkstransienter
  • Graciös försämring när distribuerad cache misslyckas

Kostnadsfördelar:

  • Minskar autentiseringsbegäranden (hantering av begränsningar)
  • Lägre Azure kostnader för autentiseringsåtgärder

Snabbstart

Kom igång snabbt med någon av följande cachekonfigurationer, beroende på din miljö.

Utveckling – minnesintern cache

I följande exempel läggs en minnesintern tokencache som är lämplig för utveckling och exempel:

using Microsoft.Identity.Web;

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

fördelar:

  • Enkel installation
  • Snabba prestanda
  • Inga externa beroenden

Nackdelar:

  • Cacheminnet gick förlorat vid omstart av appen. I en webbapp förblir användarna inloggade via cookien men måste logga in igen för att få en åtkomsttoken och fylla i cacheminnet igen
  • Inte lämplig för produktionsdistributioner med flera servrar
  • Delas inte mellan programinstanser

Produktion – distribuerad cache

För produktionsprogram, särskilt distributioner med flera servrar, använder du en distribuerad cache som backas upp av Redis eller någon annan provider:

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

fördelar:

  • Överlever omstarter av appen
  • Delas mellan alla programinstanser
  • Automatisk L1+L2-cachelagring

Nackdelar:

  • Kräver extern cacheinfrastruktur
  • Ytterligare konfigurationskomplexitet
  • Nätverksfördröjning för cacheåtgärder

Välja en cachestrategi

Använd följande beslutsflödesschema och matris för att välja den cachestrategi som passar bäst för distributionen.

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

Beslutsmatris

I följande tabell sammanfattas rekommenderade cachetyper för vanliga distributionsscenarier.

Scenario Rekommenderad cache Motivering
Lokal utveckling In-Memory Enkelhet, ingen infrastruktur behövs
Exempel/demonstrationer In-Memory Enkel installation för demonstrationer
Produktion med en server (omstarter är OK) In-Memory Acceptabelt om sessioner kan återupprättas
Produktion med flera servrar Redis Delad cache, hög prestanda, tillförlitlig
Azure värdbaserade program Azure Cache för Redis Intern Azure integrering, hanterad tjänst
Lokalt företag SQL Server Utnyttjar befintlig infrastruktur
PostgreSQL-miljöer PostgreSQL Använder befintlig PostgreSQL-databas, välbekant SQL-semantik
Miljöer med hög säkerhet SQL Server + Kryptering Datasuveränitet, kryptering av lagrad data
Testa distribuerade scenarier Distribuerat minne Testar L2-cachebeteende utan infrastruktur

Cacheimplementeringar

Microsoft. Identity.Web stöder flera cacheimplementeringar. Välj den som matchar kraven på infrastruktur och tillgänglighet.

Minnescache

När ska du använda:

  • Utveckling och testning
  • Distributioner med enskild server med acceptabelt omstartsbeteende
  • Exempel och prototyper

Configuration:

Följande kod registrerar minnesintern tokencache med standardinställningar:

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

Med anpassade alternativ:

Du kan anpassa förfallo- och storleksgränser genom att skicka alternativ:

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

→ Läs mer om minnesintern cachekonfiguration


Distribuerad cache (L2) med automatiskt L1-stöd

När ska du använda:

  • Implementeringar för flera servrar i en produktionsmiljö
  • Program som kräver cachepersistence mellan omstarter
  • Scenarier för hög tillgänglighet

Nyckelfunktion: Sedan Microsoft.Identity.Web v1.8.0 innehåller den distribuerade cachen automatiskt en minnes-intern L1-cache för prestanda och tillförlitlighet.

Lägg till Redis-reťazec pripojenia i appsettings.json:

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

Registrera sedan cachen för distribuerad token och Redis-providern i 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 för Redis

Om du vill använda Azure Cache for Redis registrerar du cachen med din Azure reťazec pripojenia:

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

Format för anslutningssträng:

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

SQL Server-cache

I följande exempel konfigureras SQL Server som den distribuerade cacheserverdelen:

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

I följande exempel konfigureras Azure Cosmos DB som den distribuerade cacheserverdelen:

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

Kräver nuget-paketet Microsoft.Extensions.Caching.Postgres.

appsettings.json:

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

Registrera sedan PostgreSQL-cachen i 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);
});

→ Läs mer om konfiguration av distribuerad cache


Försiktighet

Sessionsbaserad cachelagring har betydande begränsningar. Använd en distribuerad cache i stället.

I följande exempel visas sessionsbaserad cachning av tokens som referens:

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:

  • Problem med cookiestorlek – Stora ID-token med många anspråk orsakar problem
  • Omfångskonflikter – Kan inte användas med singleton TokenAcquisition (t.ex. Microsoft Graph SDK)
  • Sessionstillhörighet krävs – fungerar inte bra i lastbalanserade scenarier
  • Rekommenderas inte – Använd distribuerad cache i stället

Avancerad konfiguration

Med de här alternativen kan du finjustera cachebeteendet för principer för prestanda, säkerhet och borttagning.

L1-cachekontroll

L1-cachen (minnesintern) förbättrar prestandan när du använder distribuerade cacheminnen. Följande kod konfigurerar storlek och beteende för L1-cache:

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

När du ska inaktivera L1:

  • Ingen sessionstillhörighet i lastbalanseraren
  • Användare som ofta tillfrågas om MFA på grund av cacheinkonsekvens
  • Kompromiss: L2-åtkomsten är långsammare (~30 ms jämfört med ~10 ms)

Cacheborttagningsprinciper

Borttagningsprinciper styr när cachelagrade token tas bort. Följande kod anger absolut och glidande förfallotid:

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

Du kan också konfigurera borttagning via appsettings.json:

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

Rekommendationer:

  • Ange förfallotid som är längre än tokenlivslängden (token upphör vanligtvis att gälla om en timme)
  • Standard: 90 minuters glidande förfallotid
  • Balans mellan minnesanvändning och användarupplevelse
  • Tänk på: 72 timmar absolut + 2 timmar glidande för bra UX

→ Läs mer om strategier för cacheborttagning


Kryptering i viloläge

Om du vill skydda känsliga tokendata i distribuerade cacheminnen aktiverar du kryptering via ASP.NET Core Dataskydd.

En enda maskin

På en enda dator aktiverar du kryptering med den inbyggda dataskyddsprovidern:

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

Distribuerade system (flera servrar)

Viktigt!

Distribuerade system delar inte krypteringsnycklar som standard. Du måste konfigurera nyckeldelning:

Azure Key Vault (rekommenderas):

Följande kod bevarar nycklar för att Azure Blob Storage och skyddar dem med 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());

Certifikatbaserad:

Följande kod bevarar nycklar till en filresurs och skyddar dem med ett X.509-certifikat:

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"]));

→ Läs mer om kryptering och dataskydd


Överväganden för cacheprestanda

Använd följande uppskattningar för att planera cachekapacitet för ditt program.

Uppskattningar av tokenstorlek

Tokentyp Typisk storlek Per Notes
Apptoken ~2 kB Tenantenhet × Resurs Automatiskt borttagen
Användartoken ~7 KB Användare × Kundorganisation × Resurs Manuell borttagning krävs
Uppdatera tokenar Variabel User Långlivade

Minnesplanering

För 500 samtidiga användare som anropar 3 API:er:

  • Användartoken: 500 × 3 × 7 KB = 10,5 MB
  • Med omkostnader: ~15–20 MB

För 10 000 samtidiga användare:

  • Användartoken: 10 000 × 3 × 7 KB = 210 MB
  • Med omkostnader: ~300–350 MB

Rekommendation: Ange storleksgräns för L1-cache baserat på förväntade samtidiga användare.

Metodtips

Följ dessa riktlinjer för att garantera effektiv och tillförlitlig token cache.

Använda distribuerad cache i produktion – Viktigt för distributioner med flera servrar

Ange lämpliga storleksgränser för cache – Förhindra obundna minnestillväxt

Konfigurera borttagningsprinciper – Balansera UX- och minnesanvändning

Aktivera kryptering för känsliga data – Skydda token i vila

Övervaka cachehälsa – Spåra träfffrekvenser, fel och prestanda

Hantera L2-cachefel på ett korrekt sätt – L1-cachen säkerställer motståndskraft

Testa cachebeteende – Verifiera omstartsscenarier och redundans

Använd inte distribuerad minnescache i produktion – Inte beständiga eller distribuerade

Använd inte sessionscache – har betydande begränsningar

Ange inte förfallotid kortare än tokenlivslängd – Tvingar fram onödig omautentisering

Glöm inte delning av krypteringsnycklar – distribuerade system behöver delade nycklar