I den här guiden migrerar du ett konfidentiellt klientprogram från Azure Active Directory Authentication Library for .NET (ADAL.NET) till Microsofts autentiseringsbibliotek för .NET (MSAL.NET). Konfidentiella klientprogram omfattar webbappar, webb-API:er och daemonprogram som anropar en annan tjänst för egen räkning. Mer information om konfidentiella appar finns i Autentiseringsflöden och programscenarier. Om din app baseras på ASP.NET Core, se Microsoft.Identity.Web.
För appregistreringar:
- Du behöver inte skapa en ny appregistrering. (Du behåller samma klient-ID.)
- Du behöver inte ändra förauktoriseringarna (administratörsmedgivande API-behörigheter).
Migreringssteg
Hitta koden som använder ADAL.NET i din app.
Koden som använder ADAL i en konfidentiell klientapp instansierar AuthenticationContext och anropar antingen AcquireTokenByAuthorizationCode eller en åsidosättning av AcquireTokenAsync med följande parametrar:
- En
resourceId sträng. Den här variabeln är app-ID-URI:n för webb-API:et som du vill anropa.
- En instans av
IClientAssertionCertificate eller ClientAssertion. Den här instansen innehåller klientautentiseringsuppgifterna för din app för att bevisa appens identitet.
När du har upptäckt att du har appar som använder ADAL.NET installerar du MSAL.NET NuGet-paketet Microsoft. Identity.Client och uppdatera dina projektbiblioteksreferenser. Mer information finns i Installera ett NuGet-paket. Om du vill använda tokencache-serialiserare installerar du Microsoft. Identity.Web.TokenCache.
Uppdatera koden enligt det konfidentiella klientscenariot. Vissa steg är vanliga och gäller för alla konfidentiella klientscenarier. Andra steg är unika för varje scenario.
Konfidentiella klientscenarier:
Du kan ha angett en omslutning runt ADAL.NET för att hantera certifikat och cachelagring. Den här guiden använder samma metod för att illustrera migreringsprocessen från ADAL.NET till MSAL.NET. Den här koden är dock endast i demonstrationssyfte. Kopiera/klistra inte in dessa wrapper eller integrera dem i er kod som de är.
Migrera daemonappar
Daemon-scenarier använder OAuth2.0-klientens autentiseringsflöde. De kallas även tjänst-till-tjänst-anrop. Din app hämtar en token för egen räkning, inte för en användares räkning.
Ta reda på om koden använder daemonscenarier
ADAL-koden för din app använder daemonscenarier om den innehåller ett anrop till AuthenticationContext.AcquireTokenAsync med följande parametrar:
- En resurs (app-ID-URI) som en första parameter
-
IClientAssertionCertificate eller ClientAssertion som den andra parametern
AuthenticationContext.AcquireTokenAsync har ingen parameter av typen UserAssertion. Om så är fallet är din app ett webb-API och använder scenariot webb-API som anropar bakomliggande webb-API:er.
Uppdatera koden för daemonscenarier
Följande steg för att uppdatera kod gäller för alla konfidentiella klientscenarier:
- Lägg till MSAL.NET namnområdet i källkoden:
using Microsoft.Identity.Client;.
- I stället för att instansiera
AuthenticationContextanvänder du ConfidentialClientApplicationBuilder.Create för att instansiera IConfidentialClientApplication.
- I stället för strängen
resourceId använder MSAL.NET omfång. Eftersom program som använder ADAL.NET är förauktoriserade kan du alltid använda följande omfång: new string[] { $"{resourceId}/.default" }.
- Ersätt anropet till
AuthenticationContext.AcquireTokenAsync med ett anrop till IConfidentialClientApplication.AcquireTokenXXX, där XXX är beroende av ditt scenario.
I det här fallet ersätter du anropet till AuthenticationContext.AcquireTokenAsync med ett anrop till IConfidentialClientApplication.AcquireTokenClient.
Här är en jämförelse av ADAL.NET och MSAL.NET kod för daemonscenarier:
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;
}
}
Dra nytta av cachelagring av token
Om du inte konfigurerar cachelagring av token kommer tokenutfärdaren att strypa dina anrop, vilket leder till fel. Det krävs också mycket mindre för att hämta en token från cacheminnet (10–20 ms) än från ESTS (500–3 0000 ms).
Om du vill implementera en distribuerad tokencache läser du Tokencache för en webbapp eller ett webb-API (konfidentiellt klientprogram).
Läs mer om daemonscenariot och hur det implementeras med MSAL.NET eller Microsoft. Identity.Web i nya program.
Migrera ett webb-API som anropar underordnade webb-API:er
Webb-API:er som anropar underordnade webb-API:er använder OBO-flödet (OAuth2.0 on-behalf-of). Webb-API:et använder den åtkomsttoken som hämtats från HTTP-auktorisera-huvudet och validerar den här token. Denna token utbyts sedan mot en token för att anropa det underordnade webb-API:et. Den här token används som en UserAssertion instans i både ADAL.NET och MSAL.NET.
Ta reda på om koden använder OBO
ADAL-koden för din app använder OBO om den innehåller ett anrop till AuthenticationContext.AcquireTokenAsync med följande parametrar:
- En resurs (app-ID-URI) som en första parameter
-
IClientAssertionCertificate eller ClientAssertion som den andra parametern
- En parameter av typen
UserAssertion
Uppdatera koden med hjälp av OBO
Följande steg för att uppdatera kod gäller för alla konfidentiella klientscenarier:
- Lägg till MSAL.NET namnområdet i källkoden:
using Microsoft.Identity.Client;.
- I stället för att instansiera
AuthenticationContextanvänder du ConfidentialClientApplicationBuilder.Create för att instansiera IConfidentialClientApplication.
- I stället för strängen
resourceId använder MSAL.NET omfång. Eftersom program som använder ADAL.NET är förauktoriserade kan du alltid använda följande omfång: new string[] { $"{resourceId}/.default" }.
- Ersätt anropet till
AuthenticationContext.AcquireTokenAsync med ett anrop till IConfidentialClientApplication.AcquireTokenXXX, där XXX är beroende av ditt scenario.
I det här fallet ersätter vi anropet till AuthenticationContext.AcquireTokenAsync med ett anrop till IConfidentialClientApplication.AcquireTokenOnBehalfOf.
Här är en jämförelse av exempel på OBO-kod för ADAL.NET och 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;
}
}
Dra nytta av cachelagring av token
För cachelagring av token i OBOs använder du en distribuerad tokencache. Mer information finns i Tokencache för en webbapp eller webb-API (konfidentiell klientapp).
app.UseInMemoryTokenCaches(); // or a distributed token cache.
Läs mer om webb-API:er som anropar underordnade webb-API:er och hur de implementeras med MSAL.NET eller Microsoft. Identity.Web i nya appar.
Migrera en webbapp som anropar webb-API:er
Om din app använder ASP.NET Core rekommenderar vi starkt att du uppdaterar till Microsoft. Identity.Web eftersom det bearbetar allt åt dig. En snabbpresentation finns i Microsoft. Identity.Web-meddelande om allmän tillgänglighet. Mer information om hur du använder den i en webbapp finns i Varför använda Microsoft. Identity.Web i webbappar?.
Webbappar som loggar in användare och anropar webb-API:er för användarnas räkning använder Auktoriseringskodflödet OAuth2.0. Vanligtvis:
- Appen loggar in en användare genom att genomföra det första steget i auktoriseringskodflödet genom att anropa Microsofts identitetsplattforms authorize-slutpunkt. Användaren loggar in och utför multifaktorautentisering vid behov. Som ett resultat av den här åtgärden tar appen emot auktoriseringskoden. Autentiseringsbiblioteket används inte i det här skedet.
- Appen kör den andra delen av auktoriseringskodflödet. Den använder auktoriseringskoden för att hämta en åtkomsttoken, en ID-token och en uppdateringstoken. Programmet måste ange värdet
redirectUri, vilket är den URI där slutpunkten för Microsofts identitetsplattform tillhandahåller säkerhetstoken. När appen har fått den URI:n anropas AcquireTokenByAuthorizationCode vanligtvis ADAL eller MSAL för att lösa in koden och hämta en token som ska lagras i tokencacheminnet.
- Appen använder ADAL eller MSAL för att anropa
AcquireTokenSilent för att hämta token för att anropa nödvändiga webb-API:er från webbappkontrollanterna.
Ta reda på om koden använder autentiseringskodflödet
ADAL-koden för din app använder autentiseringskodflöde om den innehåller ett anrop till AuthenticationContext.AcquireTokenByAuthorizationCodeAsync.
Uppdatera koden med hjälp av auktoriseringskodflödet
Följande steg för att uppdatera kod gäller för alla konfidentiella klientscenarier:
- Lägg till MSAL.NET namnområdet i källkoden:
using Microsoft.Identity.Client;.
- I stället för att instansiera
AuthenticationContextanvänder du ConfidentialClientApplicationBuilder.Create för att instansiera IConfidentialClientApplication.
- I stället för strängen
resourceId använder MSAL.NET omfång. Eftersom program som använder ADAL.NET är förauktoriserade kan du alltid använda följande omfång: new string[] { $"{resourceId}/.default" }.
- Ersätt anropet till
AuthenticationContext.AcquireTokenAsync med ett anrop till IConfidentialClientApplication.AcquireTokenXXX, där XXX är beroende av ditt scenario.
I det här fallet ersätter du anropet till AuthenticationContext.AcquireTokenAsync med ett anrop till IConfidentialClientApplication.AcquireTokenByAuthorizationCode.
Här är en jämförelse av exempel på auktoriseringskodflöden för ADAL.NET och 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;
}
}
Anrop AcquireTokenByAuthorizationCode lägger till en token i tokencachen när auktoriseringskoden tas emot. Om du vill hämta ytterligare token för andra resurser eller klientorganisationer använder du AcquireTokenSilent i dina styrenheter.
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;
}
}
Dra nytta av cachelagring av token
Eftersom webbappen använder AcquireTokenByAuthorizationCodemåste den använda en distribuerad tokencache för cachelagring av token. Mer information finns i Tokencache för en webbapp eller ett webb-API.
app.UseInMemoryTokenCaches(); // or a distributed token cache.
Hantera undantaget MsalUiRequiredException
När kontrollanten försöker hämta en token tyst för olika omfång/resurser kan MSAL.NET utlösa en MsalUiRequiredException som förväntat om användaren behöver logga in igen eller om åtkomsten till resursen kräver fler anspråk (på grund av en princip för villkorsstyrd åtkomst). Mer information om åtgärder finns i Hantera fel och undantag i MSAL.NET.
Läs mer om webbappar som anropar webb-API:er och hur de implementeras med MSAL.NET eller Microsoft. Identity.Web i nya program.
MSAL-förmåner
Viktiga fördelar med MSAL.NET för din app är:
Återhämtningsförmåga. MSAL.NET hjälper till att göra din app elastisk genom:
- Fördelar med Microsoft Entra ID Cached Credential Service (CCS). CCS fungerar som en Microsoft Entra säkerhetskopia.
- Proaktiv förnyelse av token om API:et som du anropar aktiverar långlivade token via kontinuerlig åtkomstutvärdering.
Säkerhet. Du kan hämta PoP-token (Proof of Possession) om webb-API:et som du vill anropa kräver det. Mer information finns i Bevis på innehavstoken i MSAL.NET
Prestanda och skalbarhet. Om du inte behöver dela cacheminnet med ADAL.NET inaktiverar du den äldre cachekompatibiliteten när du skapar det konfidentiella klientprogrammet (.WithLegacyCacheCompatibility(false)) för att avsevärt öka prestandan.
app = ConfidentialClientApplicationBuilder.Create(ClientId)
.WithCertificate(certificate)
.WithAuthority(authority)
.WithLegacyCacheCompatibility(false)
.Build();
Troubleshooting
MsalServiceException
Följande felsökningsinformation gör två antaganden:
- Din ADAL.NET kod fungerade.
- Du har migrerat till MSAL genom att behålla samma klient-ID.
Om du får ett undantag med något av följande meddelanden:
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.
Felsöka undantaget med hjälp av följande steg:
- Bekräfta att du använder den senaste versionen av MSAL.NET.
- Kontrollera att den auktoritetsvärd som du angav när du byggde den konfidentiella klientappen och den auktoritetsvärd som du använde med ADAL är samma eller likvärdiga. Är det särskilt samma moln (Azure Government, Microsoft Azure som drivs av 21Vianet eller Azure Germany)?
MsalClientException
I appar för flera klientorganisationer anger du en gemensam auktoritet när du skapar appen för att rikta den mot en specifik klientorganisation, till exempel användarens klientorganisation när du anropar ett webb-API. Sedan MSAL.NET 4.37.0 kan du, när du anger .WithAzureRegion när appen skapas, inte längre ange Authority med .WithAuthority vid tokenbegäranden. Om du gör det får du följande fel när du uppdaterar från tidigare versioner av 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."
Du kan åtgärda problemet genom att ersätta .WithAuthority uttrycket AcquireTokenXXX med .WithTenantId. Ange klientorganisationen med antingen ett GUID eller ett domännamn.
Nästa steg
Läs mer om: