Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
La memorizzazione nella cache dei token è fondamentale per le prestazioni, l'affidabilità e l'esperienza utente dell'applicazione. Microsoft. Identity.Web offre strategie flessibili di memorizzazione nella cache dei token che bilanciano le prestazioni, la persistenza e l'affidabilità operativa.
Informazioni generali
Che cosa sono i token memorizzati nella cache?
Microsoft. Identity.Web memorizza nella cache diversi tipi di token:
| Tipo di token | Dimensione | Ambito | Sfratto |
|---|---|---|---|
| Token di accesso | ~2 KB | Per (utente/app, tenant, risorsa) | Automatico (basato sulla durata) |
| Token di aggiornamento | Variable | Per account utente | Manuale o basato su criteri |
| Token ID | ~2-7 KB | Per utente | Automatico |
Dove si applica la memorizzazione nella cache dei token:
- App Web che chiamano LE API - Token utente per l'accesso delegato
- API Web che chiamano API a valle - Token OBO (richiede criteri di rimozione accurati)
- Applicazioni daemon - Token per chiamate tra servizi
Perché memorizzare nella cache i token?
Vantaggi delle prestazioni:
- Riduce i round trip per Microsoft Entra ID
- Chiamate API più veloci (L1: <10ms vs L2: ~30ms vs rete: >100ms)
- Bassa latenza per gli utenti finali
Vantaggi dell'affidabilità:
- Continua a funzionare durante le interruzioni temporanee di Entra ID
- Resiliente ai temporanei di rete
- Degradazione graduale quando la cache distribuita fallisce
Vantaggi dei costi:
- Riduce le richieste di autenticazione (limitazione della frequenza)
- Costi di Azure inferiori per le operazioni di autenticazione
Avvio rapido
Sviluppo - cache in memoria
Per lo sviluppo e gli esempi, usare la cache in memoria:
using Microsoft.Identity.Web;
builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, "AzureAd")
.EnableTokenAcquisitionToCallDownstreamApi()
.AddInMemoryTokenCaches();
Vantaggi:
- Impostazione semplice
- Prestazioni veloci
- Nessuna dipendenza esterna
Svantaggi:
- Cache persa al riavvio dell'app. In una app web sarai collegato (con il cookie), ma sarà necessario ricollegarti per ottenere un token di accesso e popolare la cache dei token.
- Non adatto per le distribuzioni multiserver di produzione
- Non condiviso tra istanze dell'applicazione
Produzione - Cache distribuita
Per le applicazioni di produzione, in particolare le distribuzioni multiserver:
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_";
});
Vantaggi:
- Sopravvive ai riavvii dell'app
- Condiviso tra tutte le istanze dell'applicazione
- Memorizzazione automatica nella cache L1+L2
Svantaggi:
- Richiede l'infrastruttura della cache esterna
- Complessità aggiuntiva della configurazione
- Latenza di rete per le operazioni della cache
Scelta di una strategia di cache
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
Matrice decisionale
| Scenario | Cache consigliata | Motivazione |
|---|---|---|
| Sviluppo locale | In-Memory | Semplicità, nessuna infrastruttura necessaria |
| Esempi/dimostrazioni | In-Memory | Configurazione semplice per le dimostrazioni |
| Produzione a server singolo (riavvii possibili) | In-Memory | Accettabile se le sessioni possono essere ristabilite |
| Produzione multiserver | Redis | Cache condivisa, prestazioni elevate, affidabile |
| applicazioni ospitate su Azure | cache di Azure per Redis | Integrazione Azure nativa, servizio gestito |
| Organizzazione locale | SQL Server | Sfrutta l'infrastruttura esistente |
| Ambienti PostgreSQL | PostgreSQL | Usa il database PostgreSQL esistente, semantica SQL familiare |
| Ambienti a sicurezza elevata | SQL Server e crittografia | Residenza dei dati, crittografia in stato di inattività |
| Test di scenari distribuiti | Memoria distribuita | Verifica il comportamento della cache L2 senza infrastruttura |
Implementazioni della cache
1. In-Memory cache
Quando usare:
- Sviluppo e test
- Distribuzioni a server singolo con un comportamento di riavvio accettabile
- Esempi e prototipi
Configuration:
builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, "AzureAd")
.EnableTokenAcquisitionToCallDownstreamApi()
.AddInMemoryTokenCaches();
Con opzioni personalizzate:
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
});
→ Altre informazioni sulla configurazione della cache in memoria
2. Cache distribuita (L2) con supporto L1 automatico
Quando usare:
- Distribuzioni multiserver di produzione
- Applicazioni che richiedono la persistenza della cache tra riavvii
- Scenari di disponibilità elevata
Key Feature: Da Microsoft. Identity.Web v1.8.0, la cache distribuita include automaticamente una cache L1 in memoria per prestazioni e affidabilità.
Redis cache (scelta consigliata)
appsettings.json:
{
"ConnectionStrings": {
"Redis": "localhost:6379"
}
}
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
};
});
cache di Azure per Redis
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = builder.Configuration.GetConnectionString("AzureRedis");
options.InstanceName = "MyApp_";
});
Formato della stringa di connessione:
<cache-name>.redis.cache.windows.net:6380,password=<access-key>,ssl=True,abortConnect=False
cache di SQL Server
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);
});
cache Azure Cosmos DB
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;
});
Cache PostgreSQL
Richiede il pacchetto NuGet Microsoft.Extensions.Caching.Postgres.
appsettings.json:
{
"ConnectionStrings": {
"PostgresCache": "Host=localhost;Database=mydb;Username=myuser;Password=mypassword"
},
"PostgresCache": {
"SchemaName": "public",
"TableName": "token_cache",
"CreateIfNotExists": true
}
}
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);
});
→ Altre informazioni sulla configurazione della cache distribuita
3. Cache di sessione (non consigliata)
Attenzione
La memorizzazione nella cache basata su sessione presenta limitazioni significative:
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:
- Problemi di dimensioni dei cookie - Token ID di grandi dimensioni con molte attestazioni causano problemi
- conflitti di ambito Scope - non è possibile utilizzare con singleton
TokenAcquisition(ad esempio, Microsoft Graph SDK) - Affinità di sessione richiesta : non funziona correttamente negli scenari con carico bilanciato
- Non consigliato : usare invece la cache distribuita
Configurazione avanzata
Controllo cache L1
La cache L1 (in memoria) migliora le prestazioni quando si usano cache distribuite:
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;
});
Quando disabilitare L1:
- Nessuna affinità di sessione nel servizio di bilanciamento del carico
- Gli utenti hanno spesso richiesto l'autenticazione a più fattori a causa dell'incoerenza della cache
- Compromesso prestazionale: l'accesso a L2 è più lento (~30 ms contro ~10 ms)
Criteri di rimozione della cache
Controllare quando vengono rimossi i token memorizzati nella cache:
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);
});
In alternativa, configurare tramite appsettings.json:
{
"TokenCacheOptions": {
"AbsoluteExpirationRelativeToNow": "72:00:00",
"SlidingExpiration": "02:00:00"
}
}
builder.Services.Configure<MsalDistributedTokenCacheAdapterOptions>(
builder.Configuration.GetSection("TokenCacheOptions"));
Raccomandazioni:
- Impostare la scadenza più lunga della durata del token (in genere i token scadono in 1 ora)
- Impostazione predefinita: scadenza variabile di 90 minuti
- Bilanciare l'utilizzo della memoria e l'esperienza utente
- Si consideri: 72 ore assolute + 2 ore scorrevoli per un'esperienza utente valida
→ Altre informazioni sulle strategie di rimozione della cache
Crittografia di dati inattivi
Proteggere i dati dei token sensibili nelle cache distribuite:
Computer singolo
builder.Services.Configure<MsalDistributedTokenCacheAdapterOptions>(options =>
{
options.Encrypt = true; // Uses ASP.NET Core Data Protection
});
Sistemi distribuiti (più server)
Importante
I sistemi distribuiti non condividono le chiavi di crittografia per impostazione predefinita. È necessario configurare la condivisione delle chiavi:
Azure Key Vault (scelta consigliata):
using Microsoft.AspNetCore.DataProtection;
builder.Services.AddDataProtection()
.PersistKeysToAzureBlobStorage(new Uri(builder.Configuration["DataProtection:BlobUri"]))
.ProtectKeysWithAzureKeyVault(
new Uri(builder.Configuration["DataProtection:KeyIdentifier"]),
new DefaultAzureCredential());
Basato su certificati:
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"]));
→ Altre informazioni sulla crittografia e la protezione dei dati
Considerazioni sulle prestazioni della cache
Stime delle dimensioni dei token
| Tipo di token | Dimensioni tipiche | Per | Note |
|---|---|---|---|
| Token dell'app | ~2 KB | Risorsa × tenant | Rimosso automaticamente |
| Token utente | ~7 KB | Utente × Tenant × Risorsa | Rimozione manuale necessaria |
| Token di aggiornamento | Variable | User | Di lunga durata |
Pianificazione della memoria
Per 500 utenti simultanei che chiamano 3 API:
- Token utente: 500 × 3 × 7 KB = 10,5 MB
- Con sovraccarico: ~15-20 MB
Per 10.000 utenti simultanei:
- Token utente: 10.000 × 3 × 7 KB = 210 MB
- Con sovraccarico: ~300-350 MB
Raccomandazione: Impostare il limite di dimensioni della cache L1 in base agli utenti simultanei previsti.
Procedure consigliate
Usare la cache distribuita nell'ambiente di produzione - Essenziale per le distribuzioni multiserver
Impostare i limiti di dimensioni della cache appropriati - Impedire l'aumento non limitato della memoria
Configurare i criteri di rimozione - Bilanciare l'esperienza utente e l'utilizzo della memoria
Abilitare la crittografia per i dati sensibili - Proteggere i token a riposo
Monitorare l'integrità della cache - Tenere traccia delle percentuali di riscontri, degli errori e delle prestazioni
Gestire gli errori della cache L2 normalmente : la cache L1 garantisce la resilienza
Comportamento della cache di test - Verificare gli scenari di riavvio e il failover
Non usare la cache di memoria distribuita nell'ambiente di produzione : non persistente o distribuita
Non usare la cache delle sessioni : presenta limitazioni significative
Non impostare la scadenza più breve della durata del token - Forza l'autenticazione non necessaria
Non dimenticare la condivisione delle chiavi di crittografia - I sistemi distribuiti necessitano di chiavi condivise