Dans ce guide pratique, vous allez migrer une application cliente confidentielle de Azure Active Directory bibliothèque d'authentification pour .NET (ADAL.NET) vers Microsoft Authentication Library pour .NET (MSAL.NET). Les applications clientes confidentielles incluent les applications web, les API web et les applications démon qui appellent un autre service pour leur propre compte. Pour plus d’informations sur les applications confidentielles, consultez les flux d’authentification et les scénarios d’application. Si votre application est basée sur ASP.NET Core, consultez Microsoft. Identity.Web.
Pour les inscriptions d’applications :
- Vous n’avez pas besoin de créer un nouvel enregistrement d’application. (Vous conservez le même ID client.)
- Vous n’avez pas besoin de modifier les préauthorisations (autorisations d’API consentées par l’administrateur).
Étapes de la migration
Recherchez le code qui utilise ADAL.NET dans votre application.
Le code qui utilise ADAL dans une application cliente confidentielle crée une instance de AuthenticationContext et appelle soit AcquireTokenByAuthorizationCode, soit l’une des surcharges de AcquireTokenAsync avec les paramètres suivants :
- Chaîne
resourceId. Cette variable est l’URI d’ID d’application de l’API web que vous souhaitez appeler.
- Instance de
IClientAssertionCertificate ou ClientAssertion. Cette instance fournit les informations d’identification du client pour votre application afin de prouver l’identité de votre application.
Une fois que vous avez identifié que vous avez des applications qui utilisent ADAL.NET, installez le package NuGet MSAL.NET Microsoft.Identity.Client et mettez à jour les références de bibliothèque de votre projet. Pour plus d’informations, consultez Installer un package NuGet. Pour utiliser des sérialiseurs de cache de jetons, installez Microsoft. Identity.Web.TokenCache.
Mettez à jour le code en fonction du scénario client confidentiel. Certaines étapes sont courantes et s’appliquent à tous les scénarios clients confidentiels. Les autres étapes sont uniques à chaque scénario.
Scénarios client confidentiels :
Vous avez peut-être fourni un wrapper autour de la bibliothèque ADAL.NET pour gérer les certificats et la mise en cache. Ce guide utilise la même approche pour illustrer le processus de migration d’ADAL.NET vers MSAL.NET. Toutefois, ce code est uniquement à des fins de démonstration. Ne copiez/collez pas ces wrappers ou ne les intégrez pas dans votre code tel qu’ils le sont.
Migrer des applications de démon
Les scénarios démon utilisent le flux d’informations d’identification du client OAuth2.0. On les appelle également appels entre services. Votre application acquiert un jeton pour son propre compte, et non pour le compte d’un utilisateur.
Déterminer si votre code utilise des scénarios démon
Le code ADAL de votre application utilise des scénarios de démon s’il contient un appel à AuthenticationContext.AcquireTokenAsync avec les paramètres suivants :
- Ressource (URI d’ID d’application) en tant que premier paramètre
-
IClientAssertionCertificate ou ClientAssertion en tant que deuxième paramètre
AuthenticationContext.AcquireTokenAsync n’a pas de paramètre de type UserAssertion. Si c’est le cas, votre application est une API web et relève du scénario d’API web appelant des API web en aval.
Mettre à jour le code des scénarios de démon
Les étapes suivantes pour mettre à jour le code s’appliquent à tous les scénarios clients confidentiels :
- Ajoutez l’espace de noms MSAL.NET dans votre code source :
using Microsoft.Identity.Client;.
- Au lieu d’instancier
AuthenticationContext, utilisez ConfidentialClientApplicationBuilder.Create pour instancier IConfidentialClientApplication.
- Au lieu de la
resourceId chaîne, MSAL.NET utilise des étendues. Étant donné que les applications qui utilisent ADAL.NET sont pré-autorisées, vous pouvez toujours utiliser les étendues suivantes : new string[] { $"{resourceId}/.default" }.
- Remplacez l’appel à
AuthenticationContext.AcquireTokenAsync par un appel à IConfidentialClientApplication.AcquireTokenXXX, où XXX dépend de votre scénario.
Dans ce cas, remplacez l’appel à AuthenticationContext.AcquireTokenAsync par un appel à IConfidentialClientApplication.AcquireTokenClient.
Voici une comparaison de la bibliothèque ADAL.NET et du code MSAL.NET pour les scénarios de démon :
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
public partial class AuthWrapper
{
const string ClientId = "Guid (AppID)";
const string authority
= "https://login.microsoftonline.com/{tenant}";
// App ID URI of web API to call
const string resourceId = "https://target-api.domain.com";
X509Certificate2 certificate = LoadCertificate();
public async Task<AuthenticationResult> GetAuthenticationResult()
{
var authContext = new AuthenticationContext(authority);
var clientAssertionCert = new ClientAssertionCertificate(
ClientId,
certificate);
var authResult = await authContext.AcquireTokenAsync(
resourceId,
clientAssertionCert,
);
return authResult;
}
}
using Microsoft.Identity.Client;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
public partial class AuthWrapper
{
const string ClientId = "Guid (Application ID)";
const string authority
= "https://login.microsoftonline.com/{tenant}";
// App ID URI of web API to call
const string resourceId = "https://target-api.domain.com";
X509Certificate2 certificate = LoadCertificate();
IConfidentialClientApplication app;
public async Task<AuthenticationResult> GetAuthenticationResult()
{
var app = ConfidentialClientApplicationBuilder.Create(ClientId)
.WithCertificate(certificate)
.WithAuthority(authority)
.Build();
// Setup token caching https://learn.microsoft.com/azure/active-directory/develop/msal-net-token-cache-serialization?tabs=aspnet
// For example, for an in-memory cache with 1GB limit, use
app.AddInMemoryTokenCache(services =>
{
// Configure the memory cache options
services.Configure<MemoryCacheOptions>(options =>
{
options.SizeLimit = 1024 * 1024 * 1024; // in bytes (1 GB of memory)
});
}
var authResult = await app.AcquireTokenForClient(
new [] { $"{resourceId}/.default" })
// .WithTenantId(specificTenant)
// See https://aka.ms/msal.net/withTenantId
.ExecuteAsync()
.ConfigureAwait(false);
return authResult;
}
}
Tirer parti de la mise en cache des jetons
Si vous ne configurez pas la mise en cache des jetons, l’émetteur de jeton vous limite, ce qui entraîne des erreurs. Il faut également beaucoup moins d’obtenir un jeton à partir du cache (10-20 ms) que celui d’ESTS (500-30000 ms).
Si vous souhaitez implémenter un cache de jetons distribué, consultez Cache de jetons pour une application web ou une API web (application cliente confidentielle).
En savoir plus sur le scénario démon et la façon dont il est implémenté avec MSAL.NET ou Microsoft. Identity.Web dans les nouvelles applications.
Migrer une API web qui appelle des API web en aval
Les API web qui appellent des API web en aval utilisent le flux on-behalf-of (OBO) OAuth 2.0. L’API web utilise le jeton d’accès récupéré à partir de l’en-tête d’autorisation HTTP et valide ce jeton. Ce jeton est ensuite échangé contre un jeton pour appeler l’API web en aval. Ce jeton est utilisé comme UserAssertion instance dans ADAL.NET et MSAL.NET.
Déterminer si votre code utilise OBO
Le code ADAL de votre application utilise OBO s’il contient un appel à AuthenticationContext.AcquireTokenAsync avec les paramètres suivants :
- Ressource (URI d’ID d’application) en tant que premier paramètre
-
IClientAssertionCertificate ou ClientAssertion en tant que deuxième paramètre
- Paramètre de type
UserAssertion
Mettre à jour le code à l’aide de OBO
Les étapes suivantes pour mettre à jour le code s’appliquent à tous les scénarios clients confidentiels :
- Ajoutez l’espace de noms MSAL.NET dans votre code source :
using Microsoft.Identity.Client;.
- Au lieu d’instancier
AuthenticationContext, utilisez ConfidentialClientApplicationBuilder.Create pour instancier IConfidentialClientApplication.
- Au lieu de la
resourceId chaîne, MSAL.NET utilise des étendues. Étant donné que les applications qui utilisent ADAL.NET sont pré-autorisées, vous pouvez toujours utiliser les étendues suivantes : new string[] { $"{resourceId}/.default" }.
- Remplacez l’appel à
AuthenticationContext.AcquireTokenAsync par un appel à IConfidentialClientApplication.AcquireTokenXXX, où XXX dépend de votre scénario.
Dans ce cas, nous remplaçons l’appel à AuthenticationContext.AcquireTokenAsync par un appel à IConfidentialClientApplication.AcquireTokenOnBehalfOf.
Voici une comparaison de l'exemple de code OBO pour ADAL.NET et MSAL.NET :
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
public partial class AuthWrapper
{
const string ClientId = "Guid (AppID)";
const string authority
= "https://login.microsoftonline.com/common";
X509Certificate2 certificate = LoadCertificate();
public async Task<AuthenticationResult> GetAuthenticationResult(
string resourceId,
string tokenUsedToCallTheWebApi)
{
var authContext = new AuthenticationContext(authority);
var clientAssertionCert = new ClientAssertionCertificate(
ClientId,
certificate);
var userAssertion = new UserAssertion(tokenUsedToCallTheWebApi);
var authResult = await authContext.AcquireTokenAsync(
resourceId,
clientAssertionCert,
userAssertion,
);
return authResult;
}
}
using Microsoft.Identity.Client;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
public partial class AuthWrapper
{
const string ClientId = "Guid (Application ID)";
const string authority
= "https://login.microsoftonline.com/common";
X509Certificate2 certificate = LoadCertificate();
IConfidentialClientApplication app;
public async Task<AuthenticationResult> GetAuthenticationResult(
string resourceId,
string tokenUsedToCallTheWebApi)
{
var app = ConfidentialClientApplicationBuilder.Create(ClientId)
.WithCertificate(certificate)
.WithAuthority(authority)
.Build();
// Setup token caching https://learn.microsoft.com/azure/active-directory/develop/msal-net-token-cache-serialization?tabs=aspnet
// For example, for an in-memory cache with 1GB limit. For OBO, it is recommended to use a distributed cache like Redis.
app.AddInMemoryTokenCache(services =>
{
// Configure the memory cache options
services.Configure<MemoryCacheOptions>(options =>
{
options.SizeLimit = 1024 * 1024 * 1024; // in bytes (1 GB of memory)
});
}
var userAssertion = new UserAssertion(tokenUsedToCallTheWebApi);
var authResult = await app.AcquireTokenOnBehalfOf(
new string[] { $"{resourceId}/.default" },
userAssertion)
// .WithTenantId(specificTenant)
// See https://aka.ms/msal.net/withTenantId
.ExecuteAsync()
.ConfigureAwait(false);
return authResult;
}
}
Tirer parti de la mise en cache des jetons
Pour la mise en cache des tokens dans les OBO, utilisez un cache distribué de tokens. Pour plus d’informations, consultez Cache de jeton pour une application web ou une API web (application cliente confidentielle).
app.UseInMemoryTokenCaches(); // or a distributed token cache.
En savoir plus sur les API web appelant des API web en aval et comment elles sont implémentées avec MSAL.NET ou Microsoft. Identity.Web dans les nouvelles applications.
Migrer une application web qui appelle des API web
Si votre application utilise ASP.NET Core, nous vous recommandons vivement de mettre à jour Microsoft. Identity.Web, car il traite tout pour vous. Pour une présentation rapide, consultez l’annonce de disponibilité générale de Microsoft.Identity.Web. Pour plus d’informations sur l’utilisation dans une application web, consultez Pourquoi utiliser Microsoft. Identity.Web dans les applications web ?.
Les applications web qui connectent des utilisateurs et appellent des API web pour le compte des utilisateurs utilisent le flux de code d’autorisation OAuth2.0. Typiquement:
- L’application connecte un utilisateur en exécutant une première étape du flux de code d’autorisation en accédant au point de terminaison d’autorisation de la plateforme d’identités Microsoft. L’utilisateur se connecte et effectue des authentifications multifacteur si nécessaire. En conséquence de cette opération, l’application reçoit le code d’autorisation. La bibliothèque d’authentification n’est pas utilisée à ce stade.
- L’application exécute la deuxième étape du flux de code d’autorisation. Il utilise le code d’autorisation pour obtenir un jeton d’accès, un jeton d’ID et un jeton d’actualisation. Votre application doit fournir la valeur
redirectUri, qui correspond à l’URI auquel le point de terminaison de la plateforme d’identités Microsoft fournit les jetons de sécurité. Une fois que l’application reçoit cet URI, il appelle AcquireTokenByAuthorizationCode généralement ADAL ou MSAL pour échanger le code et obtenir un jeton qui sera stocké dans le cache de jetons.
- L’application utilise ADAL ou MSAL pour appeler
AcquireTokenSilent afin d’obtenir des jetons permettant d’appeler les API web nécessaires depuis les contrôleurs de l’application web.
Déterminer si votre code utilise le flux de code d’authentification
Le code ADAL de votre application utilise le flux de code d’authentification s’il contient un appel à AuthenticationContext.AcquireTokenByAuthorizationCodeAsync.
Mettre à jour le code à l’aide du flux de code d’autorisation
Les étapes suivantes pour mettre à jour le code s’appliquent à tous les scénarios clients confidentiels :
- Ajoutez l’espace de noms MSAL.NET dans votre code source :
using Microsoft.Identity.Client;.
- Au lieu d’instancier
AuthenticationContext, utilisez ConfidentialClientApplicationBuilder.Create pour instancier IConfidentialClientApplication.
- Au lieu de la
resourceId chaîne, MSAL.NET utilise des étendues. Étant donné que les applications qui utilisent ADAL.NET sont pré-autorisées, vous pouvez toujours utiliser les étendues suivantes : new string[] { $"{resourceId}/.default" }.
- Remplacez l’appel à
AuthenticationContext.AcquireTokenAsync par un appel à IConfidentialClientApplication.AcquireTokenXXX, où XXX dépend de votre scénario.
Dans ce cas, remplacez l’appel à AuthenticationContext.AcquireTokenAsync par un appel à IConfidentialClientApplication.AcquireTokenByAuthorizationCode.
Voici une comparaison des exemples de flux de code d'autorisation pour ADAL.NET et MSAL.NET :
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
public partial class AuthWrapper
{
const string ClientId = "Guid (AppID)";
const string authority
= "https://login.microsoftonline.com/common";
private Uri redirectUri = new Uri("host/login_oidc");
X509Certificate2 certificate = LoadCertificate();
public async Task<AuthenticationResult> GetAuthenticationResult(
string resourceId,
string authorizationCode)
{
var ac = new AuthenticationContext(authority);
var clientAssertionCert = new ClientAssertionCertificate(
ClientId,
certificate);
var authResult = await ac.AcquireTokenByAuthorizationCodeAsync(
authorizationCode,
redirectUri,
clientAssertionCert,
resourceId,
);
return authResult;
}
}
using Microsoft.Identity.Client;
using Microsoft.Identity.Web;
using System;
using System.Security.Claims;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
public partial class AuthWrapper
{
const string ClientId = "Guid (Application ID)";
const string authority
= "https://login.microsoftonline.com/{tenant}";
private Uri redirectUri = new Uri("host/login_oidc");
X509Certificate2 certificate = LoadCertificate();
public IConfidentialClientApplication CreateApplication()
{
IConfidentialClientApplication app;
app = ConfidentialClientApplicationBuilder.Create(ClientId)
.WithCertificate(certificate)
.WithAuthority(authority)
.WithRedirectUri(redirectUri.ToString())
.WithLegacyCacheCompatibility(false)
.Build();
// Add a token cache. For details about other serialization
// see https://aka.ms/msal-net-cca-token-cache-serialization
app.AddInMemoryTokenCache();
return app;
}
// Called from 'code received event'.
public async Task<AuthenticationResult> GetAuthenticationResult(
string resourceId,
string authorizationCode)
{
IConfidentialClientApplication app = CreateApplication();
var authResult = await app.AcquireTokenByAuthorizationCode(
new[] { $"{resourceId}/.default" },
authorizationCode)
.ExecuteAsync()
.ConfigureAwait(false);
return authResult;
}
}
L’appel AcquireTokenByAuthorizationCode ajoute un jeton au cache de jetons lorsque le code d’autorisation est reçu. Pour obtenir des jetons supplémentaires pour d’autres ressources ou locataires, utilisez AcquireTokenSilent dans vos contrôleurs.
public partial class AuthWrapper
{
// Called from controllers
public async Task<AuthenticationResult> GetAuthenticationResult(
string resourceId2,
string authority)
{
IConfidentialClientApplication app = CreateApplication();
AuthenticationResult authResult;
var scopes = new[] { $"{resourceId2}/.default" };
var account = await app.GetAccountAsync(ClaimsPrincipal.Current.GetMsalAccountId());
try
{
// try to get an already cached token
authResult = await app.AcquireTokenSilent(
scopes,
account)
// .WithTenantId(specificTenantId)
// See https://aka.ms/msal.net/withTenantId
.ExecuteAsync().ConfigureAwait(false);
}
catch (MsalUiRequiredException)
{
// The controller will need to challenge the user
// including asking for claims={ex.Claims}
throw;
}
return authResult;
}
}
Tirer parti de la mise en cache des jetons
Étant donné que votre application web utilise AcquireTokenByAuthorizationCode, elle doit utiliser un cache de jetons distribué pour la mise en cache des jetons. Pour plus d’informations, consultez Le cache de jetons pour une application web ou une API web.
app.UseInMemoryTokenCaches(); // or a distributed token cache.
Gestion de MsalUiRequiredException
Lorsque votre contrôleur tente d’acquérir un jeton en mode silencieux pour différentes étendues/ressources, MSAL.NET risque de lever une MsalUiRequiredException, ce qui est normal si l’utilisateur doit se reconnecter ou si l’accès à la ressource nécessite davantage de revendications (en raison d’une stratégie d’accès conditionnel). Pour plus d’informations sur l’atténuation, consultez comment gérer les erreurs et les exceptions dans MSAL.NET.
En savoir plus sur les applications web appelant des API web et comment elles sont implémentées avec MSAL.NET ou Microsoft. Identity.Web dans les nouvelles applications.
Avantages MSAL
Les principaux avantages de MSAL.NET pour votre application sont les suivants :
Résilience. MSAL.NET vous aide à rendre votre application résiliente grâce à :
- Avantages du service d’informations d’identification mises en cache (CCS) de Microsoft Entra ID. Le CCS sert de solution de secours pour Microsoft Entra.
- Renouvellement proactif des jetons si l’API que vous appelez active des jetons de longue durée via l’évaluation continue de l’accès.
Sécurité. Vous pouvez acquérir des jetons de preuve de possession (PoP) si l’API web que vous souhaitez appeler l’exige. Pour plus d’informations, consultez les jetons preuve de possession dans MSAL.NET
Performances et scalabilité. Si vous n'avez pas besoin de partager votre cache avec ADAL.NET, désactivez la compatibilité du cache hérité lorsque vous créez l'application cliente confidentielle (.WithLegacyCacheCompatibility(false)) pour augmenter considérablement les performances.
app = ConfidentialClientApplicationBuilder.Create(ClientId)
.WithCertificate(certificate)
.WithAuthority(authority)
.WithLegacyCacheCompatibility(false)
.Build();
Troubleshooting
MsalServiceException
Les informations de résolution des problèmes suivantes font deux hypothèses :
- Votre code ADAL.NET fonctionnait.
- Vous avez migré vers MSAL en conservant le même ID client.
Si vous obtenez une exception avec l’un des messages suivants :
AADSTS700027: Client assertion contains an invalid signature. [Reason - The key was not found.]
AADSTS90002: Tenant 'aaaabbbb-0000-cccc-1111-dddd2222eeee' not found. This may happen if there are no active
subscriptions for the tenant. Check to make sure you have the correct tenant ID. Check with your subscription
administrator.
Résolvez les problèmes liés à l’exception en procédant comme suit :
- Vérifiez que vous utilisez la dernière version de MSAL.NET.
- Vérifiez que l’hôte d’autorité que vous définissez lors de la génération de l’application cliente confidentielle et de l’hôte d’autorité que vous avez utilisé avec ADAL sont similaires. En particulier, le même cloud (Azure Government, Microsoft Azure géré par 21Vianet ou Azure Allemagne) ?
MsalClientException
Dans les applications multilocataires, spécifiez une autorité commune lors de la création de l’application pour cibler un locataire spécifique, par exemple, le locataire de l’utilisateur lors de l’appel d’une API web. Depuis MSAL.NET 4.37.0, lorsque vous spécifiez .WithAzureRegion au moment de la création de l’application, vous ne pouvez plus spécifier l’autorité à l’aide de .WithAuthority lors des demandes de jeton. Si vous le faites, vous obtenez l'erreur suivante lors de la mise à jour à partir des versions précédentes de MSAL.NET :
MsalClientException - "You configured WithAuthority at the request level, and also WithAzureRegion. This is not supported when the environment changes from application to request. Use WithTenantId at the request level instead."
Pour résoudre ce problème, remplacez .WithAuthority l’expression AcquireTokenXXX par .WithTenantId. Spécifiez le locataire à l’aide d’un GUID ou d’un nom de domaine.
Étapes suivantes
Pour en savoir plus :