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.
Questa guida illustra come utilizzare Microsoft.Identity.Web per la cache dei token e i pacchetti di certificati con MSAL.NET nel .NET Framework, in .NET Standard 2.0 e nelle applicazioni classiche di .NET (.NET 4.7.2+).
Informazioni sulla panoramica
A partire da Microsoft. Identity.Web 1.17+, è possibile usare Microsoft. Pacchetti di utilità Identity.Web con MSAL.NET in ambienti non ASP.NET Core.
Identificare i vantaggi dei pacchetti
| Feature | Beneficio |
|---|---|
| Serializzazione della cache dei token | Adattatori cache riutilizzabili per in-memory, SQL Server, Redis, Cosmos DB, PostgreSQL |
| Assistenti certificato | Caricamento semplificato dei certificati da Key Vault, file system o archivi di certificati |
| Estensioni delle attestazioni | Metodi di utilità per la manipolazione di ClaimsPrincipal |
| .NET Standard 2.0 | Compatibile con .NET Framework 4.7.2+, .NET Core e .NET 5+ |
| Dipendenze minime | Pacchetti mirati senza dipendenze da ASP.NET Core |
Esaminare gli scenari supportati
Gli scenari seguenti sono supportati dai pacchetti di utilità mirati.
- .NET Framework Console Applications (scenari demone)
- Desktop Applications (.NET Framework)
- Servizi di lavoro (.NET Framework)
- librerie .NET Standard 2.0 (compatibilità multipiattaforma)
- Applicazione di MSAL.NET Non Web
Annotazioni
Per ASP.NET MVC/applicazioni API Web, vedere invece OWIN Integration.
Selezionare i pacchetti
Scegliere il pacchetto corrispondente allo scenario.
Identificare i pacchetti principali per MSAL.NET
| Package | Scopo | Dipendenze | destinazione .NET |
|---|---|---|---|
| Microsoft. Identity.Web.TokenCache | Serializzatori della cache dei token, ClaimsPrincipal estensioni |
Minime | .NET Standard 2.0 |
| Microsoft. Identity.Web.Certificate | Utilità di caricamento dei certificati | Minime | .NET Standard 2.0 |
Installare i pacchetti
Usare uno dei metodi seguenti per aggiungere i pacchetti al progetto.
Gestione pacchetti Console:
# Token cache serialization
Install-Package Microsoft.Identity.Web.TokenCache
# Certificate management
Install-Package Microsoft.Identity.Web.Certificate
.NET CLI:
dotnet add package Microsoft.Identity.Web.TokenCache
dotnet add package Microsoft.Identity.Web.Certificate
Informazioni sulle limitazioni dei pacchetti principali
Il pacchetto core Microsoft.Identity.Web include le dipendenze di ASP.NET Core (Microsoft.AspNetCore.*), che:
- Non sono compatibili con ASP.NET Framework
- Aumentare le dimensioni del pacchetto inutilmente
- Creare conflitti di dipendenza
Usare invece pacchetti di destinazione per .NET Framework e .NET scenari Standard.
Configurare la serializzazione della cache dei token
Informazioni sugli adattatori della cache dei token
Microsoft. Identity.Web fornisce adattatori della cache dei token che funzionano perfettamente con MSAL.NET IConfidentialClientApplication.
Creare un client riservato con la cache dei token
L'esempio seguente crea un'applicazione client riservata e collega una cache dei token in memoria.
using Microsoft.Identity.Client;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.TokenCacheProviders;
public class MsalAppBuilder
{
private static IConfidentialClientApplication _app;
public static IConfidentialClientApplication BuildConfidentialClientApplication()
{
if (_app == null)
{
string clientId = ConfigurationManager.AppSettings["AzureAd:ClientId"];
string clientSecret = ConfigurationManager.AppSettings["AzureAd:ClientSecret"];
string tenantId = ConfigurationManager.AppSettings["AzureAd:TenantId"];
// Create the confidential client application
_app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithClientSecret(clientSecret)
.WithTenantId(tenantId)
.WithAuthority(AzureCloudInstance.AzurePublic, tenantId)
.Build();
// Add token cache serialization (choose one option below)
_app.AddInMemoryTokenCache();
}
return _app;
}
}
Scegliere le opzioni della cache dei token
Selezionare il provider di cache più adatto allo scenario di distribuzione.
Configurare la cache dei token in memoria
L'esempio seguente aggiunge una semplice cache in memoria:
using Microsoft.Identity.Web.TokenCacheProviders;
_app.AddInMemoryTokenCache();
Cache in memoria con limiti di dimensione (Microsoft.Identity.Web 1.20+)
using Microsoft.Extensions.Caching.Memory;
_app.AddInMemoryTokenCache(services =>
{
// Configure memory cache options
services.Configure<MemoryCacheOptions>(options =>
{
options.SizeLimit = 5000000; // 5 MB limit
});
});
Caratteristiche:
- Accesso rapido
- Nessuna dipendenza esterna
- Non condiviso tra processi
- Perso al riavvio dell'app
Caso d'uso: App console a istanza singola, applicazioni desktop
Configurare la cache dei token in memoria distribuita
Usare il codice seguente per aggiungere una cache distribuita in memoria per ambienti a istanze multipla:
_app.AddDistributedTokenCaches(services =>
{
// Requires: Microsoft.Extensions.Caching.Memory (NuGet)
services.AddDistributedMemoryCache();
});
Caratteristiche:
- Condiviso tra istanze dell'app
- Migliore per gli scenari con carico bilanciato
- Richiede un pacchetto NuGet aggiuntivo
- Ancora perso al riavvio dell'app
Caso d'uso: Servizi a istanze multipla con acquisizione di token accettabile
Configurare la cache dei token di SQL Server
Usare il codice seguente per aggiungere una cache SQL Server persistente distribuita:
using Microsoft.Extensions.Caching.SqlServer;
_app.AddDistributedTokenCaches(services =>
{
// Requires: Microsoft.Extensions.Caching.SqlServer (NuGet)
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = ConfigurationManager.ConnectionStrings["TokenCache"].ConnectionString;
options.SchemaName = "dbo";
options.TableName = "TokenCache";
// IMPORTANT: Set expiration above token lifetime
// Access tokens typically expire after 1 hour
options.DefaultSlidingExpiration = TimeSpan.FromMinutes(90);
});
});
Eseguire il codice SQL seguente per creare la tabella della cache richiesta:
-- Create the cache table
CREATE TABLE [dbo].[TokenCache] (
[Id] NVARCHAR(449) NOT NULL,
[Value] VARBINARY(MAX) NOT NULL,
[ExpiresAtTime] DATETIMEOFFSET NOT NULL,
[SlidingExpirationInSeconds] BIGINT NULL,
[AbsoluteExpiration] DATETIMEOFFSET NULL,
PRIMARY KEY ([Id])
);
-- Create index for performance
CREATE INDEX [Index_ExpiresAtTime] ON [dbo].[TokenCache] ([ExpiresAtTime]);
Caratteristiche:
- Persistente attraverso i riavvii
- Condiviso tra più istanze
- Affidabile e scalabile
- Richiede SQL Server configurazione
Caso d'uso: Servizi daemon di produzione, attività pianificate, ruoli di lavoro a istanze multiple
Configurare la cache dei token Redis
Usare il codice seguente per aggiungere una cache distribuita Redis ad alte prestazioni:
using StackExchange.Redis;
using Microsoft.Extensions.Caching.StackExchangeRedis;
_app.AddDistributedTokenCaches(services =>
{
// Requires: Microsoft.Extensions.Caching.StackExchangeRedis (NuGet)
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = ConfigurationManager.AppSettings["Redis:ConnectionString"];
options.InstanceName = "TokenCache_";
});
});
L'esempio seguente illustra una configurazione redis pronta per la produzione:
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = ConfigurationManager.AppSettings["Redis:ConnectionString"];
options.InstanceName = "MyDaemonApp_";
// Optional: Configure Redis options
options.ConfigurationOptions = new ConfigurationOptions
{
AbortOnConnectFail = false,
ConnectTimeout = 5000,
SyncTimeout = 5000
};
});
Caratteristiche:
- Estremamente veloce
- Condivisi tra istanze
- Persistente (con persistenza Redis abilitata)
- Richiede il server Redis
Caso d'uso: App daemon con volumi elevati, sistemi distribuiti, microservizi
Configurare la cache dei token di Cosmos DB
Usare il codice seguente per aggiungere una cache Cosmos DB distribuita a livello globale:
using Microsoft.Extensions.Caching.Cosmos;
_app.AddDistributedTokenCaches(services =>
{
// Requires: Microsoft.Extensions.Caching.Cosmos (preview)
services.AddCosmosCache(options =>
{
options.ContainerName = "TokenCache";
options.DatabaseName = "IdentityCache";
options.ClientBuilder = new CosmosClientBuilder(
ConfigurationManager.AppSettings["CosmosConnectionString"]);
options.CreateIfNotExists = true;
});
});
Caratteristiche:
- Distribuito a livello globale
- A disponibilità elevata
- Scalabilità automatica
- Latenza più elevata rispetto a Redis
- Costo più elevato
Caso d'uso: Servizi daemon globali, applicazioni con distribuzione geografica
Configurare la cache dei token PostgreSQL
Usare il codice seguente per aggiungere una cache PostgreSQL distribuita:
_app.AddDistributedTokenCaches(services =>
{
// Requires: Microsoft.Extensions.Caching.Postgres (NuGet)
services.AddDistributedPostgresCache(options =>
{
options.ConnectionString = ConfigurationManager.ConnectionStrings["PostgresCache"].ConnectionString;
options.SchemaName = ConfigurationManager.AppSettings["PostgresCache:SchemaName"];
options.TableName = ConfigurationManager.AppSettings["PostgresCache:TableName"];
options.CreateIfNotExists = bool.Parse(
ConfigurationManager.AppSettings["PostgresCache:CreateIfNotExists"] ?? "true");
// Set expiration above token lifetime.
// Access tokens typically expire after 1 hour.
options.DefaultSlidingExpiration = TimeSpan.FromMinutes(90);
});
});
Caratteristiche:
- Persistente attraverso i riavvii
- Condiviso tra più istanze
- Semantica SQL familiare
- Funziona con Database di Azure per PostgreSQL
- Richiede un server PostgreSQL
Caso d'uso: Applicazioni che già utilizzano PostgreSQL come database primario, o servizi ospitati su Azure che utilizzano Azure Database per PostgreSQL
Costruire un'applicazione daemon completa
L'esempio seguente mostra un'applicazione daemon completa che acquisisce token usando le credenziali client e una cache dei token SQL Server.
using Microsoft.Identity.Client;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.TokenCacheProviders;
using System;
using System.Threading.Tasks;
namespace DaemonApp
{
class Program
{
private static IConfidentialClientApplication _app;
static async Task Main(string[] args)
{
// Build confidential client with token cache
_app = BuildConfidentialClient();
// Acquire token for app-only access
string[] scopes = new[] { "https://graph.microsoft.com/.default" };
try
{
var result = await _app.AcquireTokenForClient(scopes)
.ExecuteAsync();
Console.WriteLine($"Token acquired successfully!");
Console.WriteLine($"Token source: {result.AuthenticationResultMetadata.TokenSource}");
Console.WriteLine($"Expires on: {result.ExpiresOn}");
// Use token to call API
await CallProtectedApi(result.AccessToken);
}
catch (MsalServiceException ex)
{
Console.WriteLine($"Error acquiring token: {ex.ErrorCode}");
Console.WriteLine($"CorrelationId: {ex.CorrelationId}");
}
}
private static IConfidentialClientApplication BuildConfidentialClient()
{
var app = ConfidentialClientApplicationBuilder
.Create(ConfigurationManager.AppSettings["ClientId"])
.WithClientSecret(ConfigurationManager.AppSettings["ClientSecret"])
.WithTenantId(ConfigurationManager.AppSettings["TenantId"])
.Build();
// Add SQL Server token cache for persistence
app.AddDistributedTokenCaches(services =>
{
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = ConfigurationManager
.ConnectionStrings["TokenCache"].ConnectionString;
options.SchemaName = "dbo";
options.TableName = "TokenCache";
options.DefaultSlidingExpiration = TimeSpan.FromMinutes(90);
});
});
return app;
}
private static async Task CallProtectedApi(string accessToken)
{
// Your API call logic
}
}
}
Gestire i certificati
Informazioni sul caricamento dei certificati
Microsoft. Identity.Web semplifica il caricamento dei certificati da varie origini per i flussi di credenziali client.
Caricare i certificati con DefaultCertificateLoader
L'esempio seguente illustra come caricare un certificato da Azure Key Vault e creare un'applicazione client riservata.
using Microsoft.Identity.Web;
using Microsoft.Identity.Client;
public class CertificateHelper
{
public static IConfidentialClientApplication CreateAppWithCertificate()
{
string clientId = ConfigurationManager.AppSettings["AzureAd:ClientId"];
string tenantId = ConfigurationManager.AppSettings["AzureAd:TenantId"];
// Define certificate source
var certDescription = CertificateDescription.FromKeyVault(
keyVaultUrl: "https://my-keyvault.vault.azure.net",
keyVaultCertificateName: "MyCertificate"
);
// Load certificate
ICertificateLoader certificateLoader = new DefaultCertificateLoader();
certificateLoader.LoadIfNeeded(certDescription);
// Create confidential client with certificate
var app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithCertificate(certDescription.Certificate)
.WithTenantId(tenantId)
.Build();
// Add token cache
app.AddInMemoryTokenCache();
return app;
}
}
Scegliere le origini dei certificati
Caricare da Azure Key Vault
Caricare un certificato archiviato in Azure Key Vault specificando l'URL dell'insieme di credenziali e il nome del certificato.
var certDescription = CertificateDescription.FromKeyVault(
keyVaultUrl: "https://my-keyvault.vault.azure.net",
keyVaultCertificateName: "MyApplicationCert"
);
ICertificateLoader loader = new DefaultCertificateLoader();
loader.LoadIfNeeded(certDescription);
var app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithCertificate(certDescription.Certificate)
.WithTenantId(tenantId)
.Build();
Prerequisiti:
- Identità gestita o Principale del Servizio con accesso a Key Vault
- pacchetto NuGet
Azure.Identity - autorizzazione Key Vault:
Getsui certificati
Caricare dall'archivio certificati
Carica un certificato dall'archivio dei certificati di Windows utilizzando il nome distintivo.
var certDescription = CertificateDescription.FromStoreWithDistinguishedName(
distinguishedName: "CN=MyApp.contoso.com",
storeName: StoreName.My,
storeLocation: StoreLocation.CurrentUser
);
ICertificateLoader loader = new DefaultCertificateLoader();
loader.LoadIfNeeded(certDescription);
var app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithCertificate(certDescription.Certificate)
.WithTenantId(tenantId)
.Build();
È anche possibile trovare un certificato tramite impronta digitale:
var certDescription = CertificateDescription.FromStoreWithThumbprint(
thumbprint: "ABCDEF1234567890ABCDEF1234567890ABCDEF12",
storeName: StoreName.My,
storeLocation: StoreLocation.LocalMachine
);
Caricare dal file system
Caricare un certificato da un file PFX nel file system locale.
var certDescription = CertificateDescription.FromPath(
path: @"C:\Certificates\MyAppCert.pfx",
password: ConfigurationManager.AppSettings["Certificate:Password"]
);
ICertificateLoader loader = new DefaultCertificateLoader();
loader.LoadIfNeeded(certDescription);
var app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithCertificate(certDescription.Certificate)
.WithTenantId(tenantId)
.Build();
Nota sulla sicurezza: Non memorizzare mai password nel codice. Usare la configurazione sicura.
Caricare dalla stringa con codifica Base64
Caricare un certificato da una stringa con codifica Base64 archiviata nella configurazione.
string base64Cert = ConfigurationManager.AppSettings["Certificate:Base64"];
var certDescription = CertificateDescription.FromBase64Encoded(
base64EncodedValue: base64Cert,
password: ConfigurationManager.AppSettings["Certificate:Password"] // Optional
);
ICertificateLoader loader = new DefaultCertificateLoader();
loader.LoadIfNeeded(certDescription);
Configurare il caricamento dei certificati da App.config
Definire le impostazioni del certificato nel file App.config e caricarle in fase di esecuzione.
App.config:
<appSettings>
<add key="AzureAd:ClientId" value="your-client-id" />
<add key="AzureAd:TenantId" value="your-tenant-id" />
<!-- Option 1: KeyVault -->
<add key="Certificate:SourceType" value="KeyVault" />
<add key="Certificate:KeyVaultUrl" value="https://my-vault.vault.azure.net" />
<add key="Certificate:KeyVaultCertificateName" value="MyCert" />
<!-- Option 2: Store -->
<!--
<add key="Certificate:SourceType" value="StoreWithThumbprint" />
<add key="Certificate:CertificateThumbprint" value="ABCD..." />
<add key="Certificate:CertificateStorePath" value="CurrentUser/My" />
-->
</appSettings>
<connectionStrings>
<add name="TokenCache"
connectionString="Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=TokenCache;Integrated Security=True;" />
</connectionStrings>
Usare il metodo helper seguente per caricare il certificato in base alla configurazione:
public static CertificateDescription GetCertificateFromConfig()
{
string sourceType = ConfigurationManager.AppSettings["Certificate:SourceType"];
return sourceType switch
{
"KeyVault" => CertificateDescription.FromKeyVault(
ConfigurationManager.AppSettings["Certificate:KeyVaultUrl"],
ConfigurationManager.AppSettings["Certificate:KeyVaultCertificateName"]
),
"StoreWithThumbprint" => CertificateDescription.FromStoreWithThumbprint(
ConfigurationManager.AppSettings["Certificate:CertificateThumbprint"],
StoreName.My,
StoreLocation.CurrentUser
),
_ => throw new ConfigurationErrorsException("Invalid certificate source type")
};
}
Esplorare le applicazioni di esempio
Esaminare questi esempi per visualizzare le implementazioni funzionanti.
Esaminare gli esempi ufficiali di Microsoft
Nella tabella seguente sono elencati esempi ufficiali che illustrano la memorizzazione nella cache dei token e il caricamento del certificato.
| Esempio | Piattaforma | Descrizione |
|---|---|---|
| ConfidentialClientTokenCache | Console (Framework .NET) | Modelli di serializzazione della cache dei token |
| active-directory-dotnetcore-daemon-v2 | Console (.NET Core) | Caricamento di certificati da Key Vault |
Seguire le migliori pratiche
Applicare questi modelli per creare applicazioni affidabili e sicure.
Seguire i modelli consigliati
1. Usare il modello singleton per IConfidentialClientApplication:
Creare una singola istanza e riutilizzarla nell'applicazione.
private static IConfidentialClientApplication _app;
public static IConfidentialClientApplication GetApp()
{
if (_app == null)
{
_app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithClientSecret(clientSecret)
.WithTenantId(tenantId)
.Build();
_app.AddDistributedTokenCaches(/* ... */);
}
return _app;
}
2. Impostare la scadenza appropriata della cache dei token:
Configurare la scadenza progressiva al di sopra della durata del token per impedire la riacquisizione non necessaria.
// Access tokens typically expire after 1 hour
// Set cache expiration ABOVE token lifetime
options.DefaultSlidingExpiration = TimeSpan.FromMinutes(90);
3. Usare l'archiviazione sicura dei certificati:
Archiviare i certificati in Azure Key Vault o in un archivio certificati protetto correttamente.
// Azure Key Vault (production)
var cert = CertificateDescription.FromKeyVault(keyVaultUrl, certName);
// Certificate store with proper permissions
var cert = CertificateDescription.FromStoreWithThumbprint(
thumbprint, StoreName.My, StoreLocation.LocalMachine);
4. Implementare una corretta gestione degli errori:
Rilevare le eccezioni MSAL e registrare l'ID di correlazione per la risoluzione dei problemi.
try
{
var result = await app.AcquireTokenForClient(scopes).ExecuteAsync();
}
catch (MsalServiceException ex)
{
logger.Error($"Token acquisition failed. CorrelationId: {ex.CorrelationId}, ErrorCode: {ex.ErrorCode}");
throw;
}
5. Utilizzare una cache distribuita per la produzione:
Una cache distribuita condivide i token tra istanze e persiste tra i riavvii.
// Correct for daemon services
app.AddDistributedTokenCaches(services =>
{
services.AddDistributedSqlServerCache(/* ... */);
});
Evitare errori comuni
1. Non creare ripetutamente nuove istanze IConfidentialClientApplication:
// Wrong - creates new instance every time
public void AcquireToken()
{
var app = ConfidentialClientApplicationBuilder.Create(clientId).Build();
// ...
}
// Correct - use singleton
private static readonly IConfidentialClientApplication _app = BuildApp();
2. Non inserire dati sensibili nel codice:
// Wrong
.WithClientSecret("supersecretvalue123")
// Correct
.WithClientSecret(ConfigurationManager.AppSettings["AzureAd:ClientSecret"])
3. Non usare la cache in memoria per i servizi a istanze multipla:
// Wrong for services with multiple instances
app.AddInMemoryTokenCache();
// Correct - use distributed cache
app.AddDistributedTokenCaches(services =>
{
services.AddDistributedSqlServerCache(/* ... */);
});
4. Non ignorare la convalida del certificato:
// Wrong - skips validation
ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, errors) => true;
// Correct - validate certificates properly
Eseguire la migrazione da ADAL.NET
Esaminare le differenze principali e aggiornare il codice per usare MSAL.NET con Microsoft. Identity.Web.
Comprendere le differenze principali
| Aspetto | ADAL.NET (deprecato) | MSAL.NET + Microsoft. Identity.Web |
|---|---|---|
| Ambiti | Basato sulle risorse (https://graph.microsoft.com) |
Basato sull'ambito (https://graph.microsoft.com/.default) |
| Token Cache | Serializzazione manuale richiesta | Adattatori integrati tramite metodi di estensione |
| Attestati | Caricamento manuale di X509Certificate2 |
DefaultCertificateLoader con più origini |
| Authority | Fissato durante la costruzione | Può essere sovrascritto per richiesta |
Confrontare esempi di migrazione
ADAL.NET (Old):
AuthenticationContext authContext = new AuthenticationContext(authority);
ClientCredential credential = new ClientCredential(clientId, clientSecret);
AuthenticationResult result = await authContext.AcquireTokenAsync(resource, credential);
MSAL.NET con Microsoft. Identity.Web (New):
var app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithClientSecret(clientSecret)
.WithTenantId(tenantId)
.Build();
app.AddInMemoryTokenCache(); // Add token cache
string[] scopes = new[] { "https://graph.microsoft.com/.default" };
AuthenticationResult result = await app.AcquireTokenForClient(scopes).ExecuteAsync();
Esplorare il contenuto correlato
Usare queste risorse per altre informazioni sugli scenari correlati.