W tym przewodniku z instrukcjami przeprowadzisz migrację poufnej aplikacji klienckiej z biblioteki Azure Active Directory Authentication Library for .NET (ADAL.NET) do Microsoft Authentication Library dla .NET (MSAL.NET). Poufne aplikacje klienckie obejmują aplikacje internetowe, internetowe interfejsy API oraz aplikacje działające w tle, które wywołują inną usługę we własnym imieniu. Aby uzyskać więcej informacji na temat poufnych aplikacji, zobacz Przepływy uwierzytelniania i scenariusze aplikacji. Jeśli aplikacja jest oparta na ASP.NET Core, zobacz Microsoft. Identity.Web.
W przypadku rejestracji aplikacji:
- Nie musisz tworzyć nowej rejestracji aplikacji. (Zachowaj ten sam identyfikator klienta).
- Nie musisz zmieniać wstępnych autoryzacji (uprawnień interfejsu API zatwierdzonych przez administratora).
Kroki migracji
Znajdź kod, który używa biblioteki ADAL.NET w aplikacji.
Kod używający ADAL w poufnej aplikacji klienckiej tworzy wystąpienie AuthenticationContext i wywołuje metodę AcquireTokenByAuthorizationCode albo jedno z przeciążeń metody AcquireTokenAsync z następującymi parametrami:
- Ciąg
resourceId. Ta zmienna zawiera identyfikator URI aplikacji internetowego interfejsu API, który chcesz wywołać.
- Wystąpienie klasy
IClientAssertionCertificate lub ClientAssertion. Ta instancja dostarcza poświadczenia klienta dla Twojej aplikacji, aby potwierdzić tożsamość Twojej aplikacji.
Po ustaleniu, że masz aplikacje korzystające z biblioteki ADAL.NET, zainstaluj pakiet NuGet MSAL.NET Microsoft.Identity.Client i zaktualizuj odwołania do bibliotek w projekcie. Aby uzyskać więcej informacji, zobacz Instalowanie pakietu NuGet. Aby użyć serializatorów pamięci podręcznej tokenów, zainstaluj Microsoft. Identity.Web.TokenCache.
Zaktualizuj kod zgodnie ze scenariuszem klienta poufnego. Niektóre kroki są typowe i stosowane we wszystkich poufnych scenariuszach klienta. Inne kroki są unikatowe dla każdego scenariusza.
Scenariusze poufnego klienta:
Być może utworzono nakładkę dla biblioteki ADAL.NET do obsługi certyfikatów i pamięci podręcznej. W tym przewodniku zastosowano to samo podejście, aby pokazać migrację z ADAL.NET do MSAL.NET. Jednak ten kod jest przeznaczony tylko do celów demonstracyjnych. Nie kopiuj/wklejaj tych otoczek ani nie integruj ich ze swoim kodem w obecnej postaci.
Migracja aplikacji typu daemon
Scenariusze demona korzystają z przepływu OAuth 2.0 poświadczeń klienta. Nazywa się je również wywołaniami między usługami. Aplikacja uzyskuje token we własnym imieniu, a nie w imieniu użytkownika.
Dowiedz się, czy kod używa scenariuszy demona
Kod biblioteki ADAL używany przez aplikację korzysta ze scenariuszy demona, jeśli zawiera wywołanie AuthenticationContext.AcquireTokenAsync z następującymi parametrami:
- Zasób (URI identyfikatora aplikacji) jako pierwszy parametr
-
IClientAssertionCertificate lub ClientAssertion jako drugi parametr
AuthenticationContext.AcquireTokenAsync nie ma parametru typu UserAssertion. Jeśli tak, to aplikacja jest internetowym interfejsem API i używa scenariusza internetowego interfejsu API wywołującego kolejne internetowe interfejsy API.
Aktualizowanie kodu scenariuszy demona
Następujące kroki aktualizacji kodu dotyczą wszystkich poufnych scenariuszy klienta:
- Dodaj przestrzeń nazw MSAL.NET w kodzie źródłowym:
using Microsoft.Identity.Client;.
- Zamiast tworzyć instancję
AuthenticationContext, użyj ConfidentialClientApplicationBuilder.Create, aby utworzyć instancję IConfidentialClientApplication.
- Zamiast ciągu
resourceId MSAL.NET używa zakresów. Ponieważ aplikacje korzystające z biblioteki ADAL.NET są wstępnie uwierzytelnione, zawsze można użyć następujących zakresów: new string[] { $"{resourceId}/.default" }.
- Zastąp wywołanie do
AuthenticationContext.AcquireTokenAsync wywołaniem do IConfidentialClientApplication.AcquireTokenXXX, gdzie XXX zależy od konkretnego scenariusza.
W takim przypadku zastąp wywołanie AuthenticationContext.AcquireTokenAsync wywołaniem IConfidentialClientApplication.AcquireTokenClient.
Oto porównanie kodu ADAL.NET i MSAL.NET dla scenariuszy demona:
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;
}
}
Korzystanie z buforowania tokenów
Jeśli nie skonfigurujesz buforowania tokenów, wystawca tokenu ograniczy Ci przepustowość, co spowoduje błędy. Uzyskanie tokenu z pamięci podręcznej (10–20 ms) trwa znacznie mniej niż z estS (500–30000 ms).
Jeśli chcesz zaimplementować rozproszoną pamięć podręczną tokenów, zobacz Pamięć podręczna tokenów dla aplikacji internetowej lub internetowego interfejsu API (poufnej aplikacji klienckiej).
Dowiedz się więcej o scenariuszu demona i sposobie implementacji za pomocą MSAL.NET lub Microsoft. Identity.Web w nowych aplikacjach.
Migrowanie internetowego interfejsu API wywołującego podrzędne internetowe interfejsy API
Internetowe API wywołujące podrzędne internetowe API używają przepływu OAuth 2.0 on-behalf-of (OBO). Internetowy interfejs API używa tokenu dostępu pobranego z nagłówka HTTP Authorize i weryfikuje ten token. Ten token jest następnie wymieniany na token w celu wywołania podrzędnego internetowego interfejsu API. Ten token jest używany jako wystąpienie UserAssertion zarówno w ADAL.NET, jak i w MSAL.NET.
Dowiedz się, czy Twój kod używa OBO
Kod biblioteki ADAL dla aplikacji używa OBO, jeśli zawiera wywołanie AuthenticationContext.AcquireTokenAsync metody z następującymi parametrami:
- Zasób (URI identyfikatora aplikacji) jako pierwszy parametr
-
IClientAssertionCertificate lub ClientAssertion jako drugi parametr
- Parametr typu
UserAssertion
Aktualizowanie kodu przy użyciu OBO
Następujące kroki aktualizacji kodu dotyczą wszystkich poufnych scenariuszy klienta:
- Dodaj przestrzeń nazw MSAL.NET w kodzie źródłowym:
using Microsoft.Identity.Client;.
- Zamiast tworzyć instancję
AuthenticationContext, użyj ConfidentialClientApplicationBuilder.Create, aby utworzyć instancję IConfidentialClientApplication.
- Zamiast ciągu
resourceId biblioteka MSAL.NET używa zakresów. Ponieważ aplikacje korzystające z biblioteki ADAL.NET są wstępnie uwierzytelnione, zawsze można użyć następujących zakresów: new string[] { $"{resourceId}/.default" }.
- Zastąp wywołanie
AuthenticationContext.AcquireTokenAsync wywołaniem IConfidentialClientApplication.AcquireTokenXXX, gdzie XXX zależy od scenariusza.
W tym przypadku zastępujemy wywołanie AuthenticationContext.AcquireTokenAsync wywołaniem IConfidentialClientApplication.AcquireTokenOnBehalfOf.
Oto porównanie przykładowego kodu OBO dla ADAL.NET i 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;
}
}
Korzystanie z buforowania tokenów
W przypadku buforowania tokenów w przepływie OBO użyj rozproszonej pamięci podręcznej tokenów. Aby uzyskać szczegółowe informacje, zobacz Pamięć podręczną tokenów dla aplikacji internetowej lub internetowego interfejsu API (aplikacji klienckiej poufnej).
app.UseInMemoryTokenCaches(); // or a distributed token cache.
Dowiedz się więcej o internetowych interfejsach API wywołujących podrzędne interfejsy API oraz o tym, jak są one implementowane za pomocą MSAL.NET lub Microsoft.Identity.Web w nowych aplikacjach.
Migrowanie aplikacji internetowej wywołującej internetowe interfejsy API
Jeśli aplikacja używa ASP.NET Core, zdecydowanie zalecamy zaktualizowanie jej do Microsoft. Identity.Web, ponieważ przetwarza wszystko za Ciebie. Aby zapoznać się z krótkim omówieniem, zobacz ogłoszenie ogólnej dostępności usługi Microsoft.Identity.Web. Aby uzyskać szczegółowe informacje na temat używania jej w aplikacji internetowej, zobacz Dlaczego warto używać Microsoft. Identity.Web w aplikacjach internetowych?.
Aplikacje internetowe logujące użytkowników i wywołujące internetowe interfejsy API w imieniu użytkowników korzystają z przepływu kodu autoryzacji OAuth2.0. Zazwyczaj:
- Aplikacja loguje użytkownika, wykonując pierwszy etap przepływu kodu autoryzacji przez skierowanie żądania do punktu końcowego autoryzacji platformy tożsamości firmy Microsoft. W razie potrzeby użytkownik loguje się i wykonuje uwierzytelnianie wieloskładnikowe. W wyniku tej operacji aplikacja otrzymuje kod autoryzacji. Biblioteka uwierzytelniania nie jest używana na tym etapie.
- Aplikacja wykonuje drugą część przepływu kodu autoryzacji. Używa kodu autoryzacji, aby uzyskać token dostępu, token tożsamości i token odświeżania. Aplikacja musi podać wartość
redirectUri, czyli adres URI, pod którym punkt końcowy platformy tożsamości firmy Microsoft udostępni tokeny zabezpieczające. Po odebraniu tego adresu URI aplikacja zwykle wywołuje AcquireTokenByAuthorizationCode dla biblioteki ADAL lub MSAL, aby wymienić kod i uzyskać token, który będzie przechowywany w pamięci podręcznej tokenów.
- Aplikacja używa biblioteki ADAL lub MSAL do wywołania
AcquireTokenSilent w celu uzyskania tokenów potrzebnych do wywoływania niezbędnych internetowych interfejsów API z kontrolerów aplikacji internetowej.
Sprawdź, czy Twój kod używa przepływu kodu autoryzacji
Kod biblioteki ADAL dla aplikacji używa przepływu kodu uwierzytelniania, jeśli zawiera wywołanie metody AuthenticationContext.AcquireTokenByAuthorizationCodeAsync.
Zaktualizuj kod, używając przepływu kodu autoryzacyjnego
Następujące kroki aktualizacji kodu dotyczą wszystkich poufnych scenariuszy klienta:
- Dodaj przestrzeń nazw MSAL.NET w kodzie źródłowym:
using Microsoft.Identity.Client;.
- Zamiast tworzyć instancję
AuthenticationContext, użyj ConfidentialClientApplicationBuilder.Create, aby utworzyć instancję IConfidentialClientApplication.
- Zamiast ciągu
resourceId MSAL.NET używa zakresów. Ponieważ aplikacje korzystające z biblioteki ADAL.NET są wstępnie uwierzytelnione, zawsze można użyć następujących zakresów: new string[] { $"{resourceId}/.default" }.
- Zastąp wywołanie do
AuthenticationContext.AcquireTokenAsync wywołaniem do IConfidentialClientApplication.AcquireTokenXXX, gdzie XXX zależy od konkretnego scenariusza.
W takim przypadku zastąp wywołanie AuthenticationContext.AcquireTokenAsync wywołaniem IConfidentialClientApplication.AcquireTokenByAuthorizationCode.
Oto porównanie przykładowych przepływów uwierzytelniania z kodem autoryzacyjnym dla ADAL.NET i 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;
}
}
Wywołanie AcquireTokenByAuthorizationCode powoduje dodanie tokenu do pamięci podręcznej tokenów po odebraniu kodu autoryzacji. Aby uzyskać dodatkowe tokeny dla innych zasobów lub dzierżaw, użyj AcquireTokenSilent w kontrolerach.
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;
}
}
Korzystanie z buforowania tokenów
Ponieważ aplikacja internetowa używa AcquireTokenByAuthorizationCode, musi korzystać z rozproszonej pamięci podręcznej tokenów do buforowania tokenów. Aby uzyskać szczegółowe informacje, zobacz Pamięć podręczna tokenów dla aplikacji internetowej lub internetowego interfejsu API.
app.UseInMemoryTokenCaches(); // or a distributed token cache.
Obsługa wyjątku MsalUiRequiredException
Gdy kontroler próbuje uzyskać token bez interakcji dla różnych zakresów/zasobów, MSAL.NET może zgodnie z oczekiwaniami zgłosić wyjątek MsalUiRequiredException, jeśli użytkownik musi zalogować się ponownie lub jeśli dostęp do zasobu wymaga dodatkowych oświadczeń (z powodu zasad dostępu warunkowego). Aby uzyskać szczegółowe informacje na temat ograniczania ryzyka, zobacz jak obsługiwać błędy i wyjątki w MSAL.NET.
Dowiedz się więcej o aplikacjach internetowych wywołujących internetowe interfejsy API i sposobie ich implementacji za pomocą MSAL.NET lub Microsoft. Identity.Web w nowych aplikacjach.
Korzyści z biblioteki MSAL
Najważniejsze korzyści z MSAL.NET dla aplikacji obejmują:
Odporność. MSAL.NET pomaga zapewnić odporność aplikacji za pomocą:
- korzyści z usługi Microsoft Entra ID Cached Credential Service (CCS). Usługa CCS działa jako kopia zapasowa Microsoft Entra.
- Proaktywne odnawianie tokenów, jeśli interfejs API, który wywołujesz, umożliwia tokeny długoterminowe dzięki funkcji ciągłej oceny dostępu.
Zabezpieczenia. Tokeny Weryfikacji posiadania (PoP) można uzyskać, jeśli internetowy interfejs API, który chcesz wywołać, wymaga tego tokenu. Aby uzyskać szczegółowe informacje, zobacz Dowód posiadania tokenów w MSAL.NET
Wydajność i skalowalność. Jeśli nie musisz współdzielić pamięci podręcznej z ADAL.NET, wyłącz zgodność ze starszą wersją pamięci podręcznej podczas tworzenia poufnej aplikacji klienckiej (.WithLegacyCacheCompatibility(false)), aby znacząco zwiększyć wydajność.
app = ConfidentialClientApplicationBuilder.Create(ClientId)
.WithCertificate(certificate)
.WithAuthority(authority)
.WithLegacyCacheCompatibility(false)
.Build();
Troubleshooting
MsalServiceException
Następujące informacje dotyczące rozwiązywania problemów zawierają dwa założenia:
- Kod biblioteki ADAL.NET działał.
- Przeprowadzono migrację do MSAL, zachowując ten sam identyfikator klienta.
Jeśli pojawi się wyjątek z jednym z poniższych komunikatów:
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.
Rozwiąż problem z wyjątkiem, wykonując następujące kroki:
- Upewnij się, że używasz najnowszej wersji MSAL.NET.
- Upewnij się, że host autoryzacji ustawiony podczas tworzenia poufnej aplikacji klienckiej oraz host autoryzacji używany z biblioteką ADAL są takie same lub podobne. W szczególności czy jest to ta sama chmura (Azure Government, Microsoft Azure obsługiwana przez firmę 21Vianet, czy Azure Germany)?
MsalClientException
W aplikacjach wielodostępnych określ wspólny punkt autoryzacji podczas tworzenia aplikacji, aby wskazać konkretną dzierżawę, na przykład dzierżawę użytkownika podczas wywoływania internetowego interfejsu API. Od wersji MSAL.NET 4.37.0 po ustawieniu .WithAzureRegion podczas tworzenia aplikacji nie można już określać elementu Authority za pomocą .WithAuthority podczas żądań tokenu. Jeśli to zrobisz, podczas aktualizowania z poprzednich wersji programu MSAL.NET zostanie wyświetlony następujący błąd:
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."
Aby rozwiązać ten problem, zastąp wyrażenie .WithAuthority AcquireTokenXXX wyrażeniem .WithTenantId. Określ dzierżawę przy użyciu identyfikatora GUID lub nazwy domeny.
Następne kroki
Dowiedz się więcej o: