Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Ce guide vous montre comment utiliser les packages Microsoft.Identity.Web pour le cache de jetons et les certificats avec MSAL.NET dans .NET Framework, .NET Standard 2.0, et les applications .NET classiques (.NET 4.7.2+).
Comprendre la vue d’ensemble
À compter de Microsoft. Identity.Web 1.17+, vous pouvez utiliser Microsoft. Packages utilitaires Identity.Web avec MSAL.NET dans des environnements non ASP.NET Core.
Identifier les avantages du package
| Fonctionnalité | Avantage |
|---|---|
| Sérialisation du cache de jetons | Adaptateurs de cache réutilisables pour la mémoire, SQL Server, Redis, Cosmos DB, PostgreSQL |
| Assistants de certificats | Chargement simplifié des certificats à partir de KeyVault, du système de fichiers ou des magasins de certificats |
| Extensions de revendications | Méthodes utilitaires de manipulation de ClaimsPrincipal |
| .NET Standard 2.0 | Compatible avec .NET Framework 4.7.2+, .NET Core et .NET 5+ |
| Dépendances minimales | Packages ciblés sans dépendances ASP.NET Core |
Passer en revue les scénarios pris en charge
Les scénarios suivants sont pris en charge avec les packages utilitaires ciblés.
- applications de console .NET Framework (scénarios de démon)
- Applications de bureau (Framework .NET)
- Worker Services (.NET Framework)
- .NET Bibliothèques Standard 2.0 (compatibilité multiplateforme)
- Applications non web de MSAL.NET
Note
Pour les applications d’API ASP.NET MVC/Web, consultez OWIN Integration à la place.
Sélectionner des packages
Choisissez le package qui correspond à votre scénario.
Identifier les packages principaux pour MSAL.NET
| Package | Objectif | Dépendances | plateforme cible .NET |
|---|---|---|---|
| Microsoft. Identity.Web.TokenCache | Sérialiseurs de cache de jetons, ClaimsPrincipal extensions |
Minimales | .NET Standard 2.0 |
| Microsoft. Identity.Web.Certificate | Utilitaires de chargement de certificat | Minimales | .NET Standard 2.0 |
Installer des packages
Utilisez l’une des méthodes suivantes pour ajouter les packages à votre projet.
Gestionnaire de package 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
Comprendre les limitations de package de base
Le package principal Microsoft.Identity.Web inclut des dépendances ASP.NET Core (Microsoft.AspNetCore.*), qui :
- Ne sont pas compatibles avec ASP.NET Framework
- Augmenter inutilement la taille du package
- Créer des conflits de dépendances
Utilisez plutôt des packages ciblés pour les scénarios .NET Framework et .NET Standard.
Configurer la sérialisation du cache de jetons
Comprendre les adaptateurs de cache de jetons
Microsoft.Identity.Web fournit des adaptateurs de cache de jetons qui fonctionnent en toute transparence avec les IConfidentialClientApplication de MSAL.NET.
Créer un client confidentiel avec le cache de jetons
L’exemple suivant crée une application cliente confidentielle et attache un cache de jetons en mémoire.
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;
}
}
Choisir les options de cache de jeton
Sélectionnez le fournisseur de cache qui correspond le mieux à votre scénario de déploiement.
Configurer le cache de jetons en mémoire
L’exemple suivant ajoute un cache en mémoire simple :
using Microsoft.Identity.Web.TokenCacheProviders;
_app.AddInMemoryTokenCache();
Cache en mémoire avec des limites de taille (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
});
});
Caractéristiques:
- Accès rapide
- Aucune dépendance externe
- Non partagé entre les processus
- Perdu lors du redémarrage de l’application
Cas d’usage : Applications console à instance unique, applications de bureau
Configurer le cache de jetons distribué en mémoire
Utilisez le code suivant pour ajouter un cache distribué en mémoire pour les environnements multi-instances :
_app.AddDistributedTokenCaches(services =>
{
// Requires: Microsoft.Extensions.Caching.Memory (NuGet)
services.AddDistributedMemoryCache();
});
Caractéristiques:
- Partagé entre les instances d’application
- Mieux adapté aux scénarios à charge équilibrée
- Nécessite un package NuGet supplémentaire
- Toujours perdu lors du redémarrage de l’application
Cas d'utilisation : Services multi-instances avec réacquisition de jeton acceptable
Configurer le cache de jetons SQL Server
Utilisez le code suivant pour ajouter un cache de SQL Server distribué persistant :
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);
});
});
Exécutez le code SQL suivant pour créer la table de cache requise :
-- 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]);
Caractéristiques:
- Persistant lors des redémarrages
- Partagé entre plusieurs instances
- Fiable et scalable
- Nécessite l'installation de SQL Server
Cas d’usage : Les services démon de production, les tâches planifiées, processus multi-instances
Configurer le cache de jetons Redis
Utilisez le code suivant pour ajouter un cache distribué Redis hautes performances :
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’exemple suivant montre une configuration Redis prête pour la production :
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
};
});
Caractéristiques:
- Extrêmement rapide
- Partagé entre les instances
- Persistant (avec la persistance Redis activée)
- Nécessite le serveur Redis
Cas d’usage : Applications démon de volume élevé, systèmes distribués, microservices
Configurer le cache de jeton Cosmos DB
Utilisez le code suivant pour ajouter un cache Cosmos DB distribué globalement :
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;
});
});
Caractéristiques:
- Distribué globalement
- Hautement disponible
- Mise à l’échelle automatique
- Latence plus élevée que Redis
- Coût plus élevé
Cas d’usage : Services démon globaux, applications géo-distribuées
Configurer le cache de jeton PostgreSQL
Utilisez le code suivant pour ajouter un cache PostgreSQL distribué :
_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);
});
});
Caractéristiques:
- Persistant lors des redémarrages
- Partagé entre plusieurs instances
- Sémantique SQL familière
- Fonctionne avec Azure Database pour PostgreSQL
- Nécessite un serveur PostgreSQL
Cas d'utilisation : Applications utilisant déjà PostgreSQL comme base de données principale, ou services hébergés sur Azure en utilisant Azure Database pour PostgreSQL
Générer une application démon complète
L’exemple suivant montre une application démon complète qui acquiert des jetons à l’aide des informations d’identification du client et d’un cache de jetons 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
}
}
}
Gérer des certificats
Comprendre le chargement des certificats
Microsoft. Identity.Web simplifie le chargement de certificats à partir de différentes sources pour les flux d’informations d’identification du client.
Charger des certificats avec DefaultCertificateLoader
L’exemple suivant montre comment charger un certificat à partir de Azure Key Vault et créer une application cliente confidentielle.
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;
}
}
Choisir des sources de certificat
Charger à partir de Azure Key Vault
Chargez un certificat stocké dans Azure Key Vault en spécifiant l’URL du coffre et le nom du certificat.
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();
Configuration requise :
- Identité managée ou principal de service avec accès Key Vault
- package NuGet
Azure.Identity - autorisation Key Vault :
Getsur les certificats
Charger depuis le référentiel de certificats
Chargez un certificat à partir du magasin de certificats Windows par nom distingué.
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();
Vous pouvez également trouver un certificat par empreinte numérique :
var certDescription = CertificateDescription.FromStoreWithThumbprint(
thumbprint: "ABCDEF1234567890ABCDEF1234567890ABCDEF12",
storeName: StoreName.My,
storeLocation: StoreLocation.LocalMachine
);
Charger à partir du système de fichiers
Chargez un certificat à partir d’un fichier PFX sur le système de fichiers local.
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();
Note de sécurité : Ne codez jamais en dur les mots de passe. Utilisez la configuration sécurisée.
Charger à partir de la chaîne encodée en Base64
Chargez un certificat à partir d’une chaîne encodée en Base64 stockée dans la configuration.
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);
Configurer le chargement de certificat à partir de App.config
Définissez les paramètres de certificat dans votre fichier App.config et chargez-les au moment de l’exécution.
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>
Utilisez la méthode d’assistance suivante pour charger le certificat en fonction de la configuration :
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")
};
}
Explorer des exemples d’applications
Passez en revue ces exemples pour voir les implémentations de travail.
Examiner les exemples officiels de Microsoft
Le tableau suivant répertorie les exemples officiels qui illustrent la mise en cache des jetons et le chargement des certificats.
| Exemple | Plate-forme | Description |
|---|---|---|
| ConfidentialClientTokenCache | Console (.NET Framework) | Modèles de sérialisation du cache de jetons |
| active-directory-dotnetcore-daemon-v2 | Console (.NET Core) | Chargement de certificat à partir de Key Vault |
Suivre les bonnes pratiques
Appliquez ces modèles pour créer des applications fiables et sécurisées.
Suivez les modèles recommandés
1. Utilisez le modèle singleton pour IConfidentialClientApplication :
Créez une instance unique et réutilisez-la dans votre application.
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. Définissez l’expiration appropriée du cache de jeton :
Configurez l’expiration glissante au-dessus de la durée de vie du jeton pour éviter une ré-acquisition inutile.
// Access tokens typically expire after 1 hour
// Set cache expiration ABOVE token lifetime
options.DefaultSlidingExpiration = TimeSpan.FromMinutes(90);
3. Utilisez le stockage de certificats sécurisé :
Stockez des certificats dans Azure Key Vault ou un magasin de certificats sécurisé correctement.
// 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. Implémentez une gestion des erreurs appropriée :
Interceptez les exceptions MSAL et journalisez l’ID de corrélation pour la résolution des problèmes.
try
{
var result = await app.AcquireTokenForClient(scopes).ExecuteAsync();
}
catch (MsalServiceException ex)
{
logger.Error($"Token acquisition failed. CorrelationId: {ex.CorrelationId}, ErrorCode: {ex.ErrorCode}");
throw;
}
5. Utilisez un cache distribué pour la production :
Un cache distribué partage des jetons entre les instances et persiste à travers les redémarrages.
// Correct for daemon services
app.AddDistributedTokenCaches(services =>
{
services.AddDistributedSqlServerCache(/* ... */);
});
Éviter les erreurs courantes
1. Ne créez pas de nouvelles instances IConfidentialClientApplication à plusieurs reprises :
// 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. Ne codez pas les secrets en dur :
// Wrong
.WithClientSecret("supersecretvalue123")
// Correct
.WithClientSecret(ConfigurationManager.AppSettings["AzureAd:ClientSecret"])
3. N’utilisez pas de cache en mémoire pour les services multi-instances :
// Wrong for services with multiple instances
app.AddInMemoryTokenCache();
// Correct - use distributed cache
app.AddDistributedTokenCaches(services =>
{
services.AddDistributedSqlServerCache(/* ... */);
});
4. N’ignorez pas la validation des certificats :
// Wrong - skips validation
ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, errors) => true;
// Correct - validate certificates properly
Migrer à partir d’ADAL.NET
Passez en revue les principales différences et mettez à jour votre code pour utiliser MSAL.NET avec Microsoft. Identity.Web.
Comprendre les principales différences
| Aspect | ADAL.NET (déconseillé) | MSAL.NET + Microsoft. Identity.Web |
|---|---|---|
| Étendues | Basé sur les ressources (https://graph.microsoft.com) |
Basé sur la portée (https://graph.microsoft.com/.default) |
| Cache de jetons | Sérialisation manuelle requise | Adapteurs intégrés via des méthodes d'extension |
| Certificats | Chargement manuel du certificat X509Certificate2 |
DefaultCertificateLoader avec plusieurs sources |
| Authority | Fixé lors de la construction | Peut être substitué par requête |
Comparer des exemples de migration
ADAL.NET (ancien) :
AuthenticationContext authContext = new AuthenticationContext(authority);
ClientCredential credential = new ClientCredential(clientId, clientSecret);
AuthenticationResult result = await authContext.AcquireTokenAsync(resource, credential);
MSAL.NET avec Microsoft. Identity.Web (Nouveau) :
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();
Explorer le contenu associé
Utilisez ces ressources pour en savoir plus sur les scénarios connexes.