In deze instructies migreert u een vertrouwelijke clienttoepassing van Azure Active Directory Authentication Library voor .NET (ADAL.NET) naar Microsoft Authentication Library voor .NET (MSAL.NET). Vertrouwelijke clienttoepassingen omvatten web-apps, web-API's en daemon-toepassingen die namens hen een andere service aanroepen. Zie Verificatiestromen en toepassingsscenario's voor meer informatie over vertrouwelijke apps. Als uw app is gebaseerd op ASP.NET Core, raadpleeg dan Microsoft.Identity.Web.
Voor app-registraties:
- U hoeft geen nieuwe app-registratie te maken. (U behoudt dezelfde client-id.)
- U hoeft de verificatie vooraf niet te wijzigen (api-machtigingen met beheerderstoestemming).
Migratiestappen
Zoek de code die gebruikmaakt van ADAL.NET in uw app.
De code die ADAL gebruikt in een vertrouwelijke client-app instantieert AuthenticationContext en roept ofwel AcquireTokenByAuthorizationCode of een override van AcquireTokenAsync aan met de volgende parameters:
- Een
resourceId tekenreeks. Deze variabele is de app-id-URI van de web-API die u wilt aanroepen.
- Een exemplaar van
IClientAssertionCertificate of ClientAssertion. Dit exemplaar biedt de clientreferenties voor uw app om de identiteit van uw app te bewijzen.
Nadat u hebt vastgesteld dat u apps hebt die gebruikmaken van ADAL.NET installeert u het MSAL.NET NuGet-pakket Microsoft. Identity.Client en werk uw projectbibliotheekverwijzingen bij. Zie Een NuGet-pakket installeren voor meer informatie. Als u serializers voor tokencache wilt gebruiken, installeert u Microsoft. Identity.Web.TokenCache.
Werk de code bij volgens het vertrouwelijke clientscenario. Sommige stappen zijn gebruikelijk en zijn van toepassing op alle vertrouwelijke clientscenario's. Andere stappen zijn uniek voor elk scenario.
Vertrouwelijke cliëntscenario's:
Mogelijk hebt u een wrapper om ADAL.NET heen gemaakt voor het afhandelen van certificaten en caching. In deze handleiding wordt dezelfde benadering gebruikt om het migratieproces van ADAL.NET naar MSAL.NET te illustreren. Deze code is echter alleen voor demonstratiedoeleinden. Kopieer en plak deze wrappers niet of integreer ze niet in uw code zoals ze zijn.
Daemon-apps migreren
Daemon-scenario's maken gebruik van de OAuth2.0-clientreferentiestroom. Ze worden ook wel service-naar-service-aanroepen genoemd. Uw app verwerft zelf een token, niet namens een gebruiker.
Ontdek of uw code daemon-scenario's gebruikt
De ADAL-code voor uw app maakt gebruik van daemon-scenario's als deze een aanroep bevat AuthenticationContext.AcquireTokenAsync met de volgende parameters:
- Een resource (app-id-URI) als eerste parameter
-
IClientAssertionCertificate of ClientAssertion als de tweede parameter
AuthenticationContext.AcquireTokenAsync heeft geen parameter van het type UserAssertion. Als dit het geval is, is uw app een web-API en wordt het scenario voor het aanroepen van downstream-web-API's gebruikt.
De code van daemon-scenario's bijwerken
De volgende stappen voor het bijwerken van code zijn van toepassing op alle vertrouwelijke clientscenario's:
- Voeg de MSAL.NET naamruimte toe in de broncode:
using Microsoft.Identity.Client;.
- Gebruik
ConfidentialClientApplicationBuilder.Create om IConfidentialClientApplication te instantiëren in plaats van AuthenticationContext.
- In plaats van de tekenreeks
resourceId gebruikt MSAL.NET scopes. Omdat toepassingen die ADAL.NET gebruiken vooraf zijn geautoriseerd, kunt u altijd de volgende machtigingen gebruiken: new string[] { $"{resourceId}/.default" }
- Vervang de aanroep naar
AuthenticationContext.AcquireTokenAsync door een aanroep naar IConfidentialClientApplication.AcquireTokenXXX, waarbij XXX afhankelijk is van uw scenario.
Vervang in dit geval de aanroep naar AuthenticationContext.AcquireTokenAsync een aanroep naar IConfidentialClientApplication.AcquireTokenClient.
Hier volgt een vergelijking van ADAL.NET en MSAL.NET code voor daemon-scenario's:
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;
}
}
Profiteer van token-caching
Als u geen tokencaching instelt, wordt u door de tokenverlener beperkt, wat resulteert in fouten. Het kost ook veel minder om een token op te halen uit de cache (10-20 ms) dan van ESTS (500-30000ms).
Als u een gedistribueerde tokencache wilt implementeren, raadpleegt u tokencache voor een web-app of web-API (vertrouwelijke clienttoepassing).
Meer informatie over het daemon-scenario en hoe het wordt geïmplementeerd met MSAL.NET of Microsoft. Identity.Web in nieuwe toepassingen.
Een web-API migreren die downstream-web-API's aanroept
Web-API's die onderliggende web-API's aanroepen, gebruiken de OAuth 2.0-on-behalf-of (OBO)-stroom. De web-API maakt gebruik van het toegangstoken dat is opgehaald uit de HTTP-autorisatieheader en valideert dit token. Dit token wordt vervolgens uitgewisseld met een token om de downstream web-API aan te roepen. Dit token wordt gebruikt als een UserAssertion instantie in zowel ADAL.NET als MSAL.NET.
Ontdek of uw code gebruikmaakt van OBO
De ADAL-code voor uw app gebruikt OBO als deze een aanroep bevat AuthenticationContext.AcquireTokenAsync met de volgende parameters:
- Een resource (app-id-URI) als eerste parameter
-
IClientAssertionCertificate of ClientAssertion als de tweede parameter
- Een parameter van het type
UserAssertion
De code bijwerken met behulp van OBO
De volgende stappen voor het bijwerken van code zijn van toepassing op alle vertrouwelijke clientscenario's:
- Voeg de MSAL.NET naamruimte toe in de broncode:
using Microsoft.Identity.Client;.
- Gebruik
ConfidentialClientApplicationBuilder.Create om IConfidentialClientApplication te instantiëren in plaats van AuthenticationContext.
- In plaats van de tekenreeks
resourceId gebruikt MSAL.NET scopes. Omdat toepassingen die ADAL.NET gebruiken vooraf zijn geautoriseerd, kunt u altijd de volgende machtigingen gebruiken: new string[] { $"{resourceId}/.default" }
- Vervang de aanroep naar
AuthenticationContext.AcquireTokenAsync door een aanroep naar IConfidentialClientApplication.AcquireTokenXXX, waarbij XXX afhankelijk is van uw scenario.
In dit geval vervangen we de aanroep van AuthenticationContext.AcquireTokenAsync door een aanroep van IConfidentialClientApplication.AcquireTokenOnBehalfOf.
Hier volgt een vergelijking van voorbeeld-OBO-code voor ADAL.NET en 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;
}
}
Profiteer van token-caching
Voor tokencaching in OBO's gebruikt u een gedistribueerde tokencache. Zie Tokencache voor een web-app of web-API (vertrouwelijke client-app) voor meer informatie.
app.UseInMemoryTokenCaches(); // or a distributed token cache.
Meer informatie over web-API's die downstream-web-API's aanroepen en hoe deze worden geïmplementeerd met MSAL.NET of Microsoft. Identity.Web in nieuwe apps.
Een web-app migreren die web-API's aanroept
Als uw app gebruikmaakt van ASP.NET Core, raden we u ten zeerste aan om bij te werken naar Microsoft. Identity.Web omdat alles voor u wordt verwerkt. Zie voor een korte presentatie de aankondiging van algemene beschikbaarheid van Microsoft.Identity.Web. Zie Waarom Microsoft.Identity.Web gebruiken in web-apps? voor meer informatie over hoe u het in een web-app gebruikt.
Web-apps die gebruikers aanmelden en web-API's aanroepen namens gebruikers, maken gebruik van de OAuth2.0-autorisatiecodestroom. Meestal:
- De app meldt een gebruiker aan door de eerste stap van de autorisatiecodestroom uit te voeren via het autorisatie-eindpunt van het Microsoft identity platform. De gebruiker meldt zich aan en voert indien nodig meervoudige verificaties uit. Als resultaat van deze bewerking ontvangt de app de autorisatiecode. De verificatiebibliotheek wordt in deze fase niet gebruikt.
- De app voert het tweede deel van de autorisatiecodestroom uit. Hierbij wordt de autorisatiecode gebruikt om een toegangstoken, een id-token en een vernieuwingstoken op te halen. Uw toepassing moet de waarde opgeven. Dit is de
redirectUri URI waarin het Microsoft identity platform-eindpunt de beveiligingstokens levert. Nadat de app die URI heeft ontvangen, roept deze doorgaans AcquireTokenByAuthorizationCode aan voor ADAL of MSAL om de code in te wisselen en een token op te halen dat wordt opgeslagen in de tokencache.
- De app gebruikt ADAL of MSAL om
AcquireTokenSilent aan te roepen en tokens op te halen voor het aanroepen van de benodigde web-API's vanuit de web-appcontrollers.
Controleren of uw code gebruikmaakt van de verificatiecodestroom
De ADAL-code voor uw app maakt gebruik van een verificatiecodestroom als deze een aanroep naar AuthenticationContext.AcquireTokenByAuthorizationCodeAsyncbevat.
De code bijwerken met behulp van de autorisatiecodestroom
De volgende stappen voor het bijwerken van code zijn van toepassing op alle vertrouwelijke clientscenario's:
- Voeg de MSAL.NET naamruimte toe in de broncode:
using Microsoft.Identity.Client;.
- Gebruik
ConfidentialClientApplicationBuilder.Create om IConfidentialClientApplication te instantiëren in plaats van AuthenticationContext.
- In plaats van de tekenreeks
resourceId gebruikt MSAL.NET scopes. Omdat toepassingen die ADAL.NET gebruiken vooraf zijn geautoriseerd, kunt u altijd de volgende machtigingen gebruiken: new string[] { $"{resourceId}/.default" }
- Vervang de aanroep naar
AuthenticationContext.AcquireTokenAsync door een aanroep naar IConfidentialClientApplication.AcquireTokenXXX, waarbij XXX afhankelijk is van uw scenario.
Vervang in dit geval de aanroep naar AuthenticationContext.AcquireTokenAsync een aanroep naar IConfidentialClientApplication.AcquireTokenByAuthorizationCode.
Hier volgt een vergelijking van voorbeeldautorisatiecodestromen voor ADAL.NET en 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;
}
}
Aanroepen AcquireTokenByAuthorizationCode voegt een token toe aan de tokencache wanneer de autorisatiecode wordt ontvangen. Als u extra tokens voor andere bronnen of tenants wilt verkrijgen, gebruikt u AcquireTokenSilent in uw controllers.
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;
}
}
Profiteer van token-caching
Omdat uw web-app gebruikmaakt AcquireTokenByAuthorizationCode, moet deze een gedistribueerde tokencache gebruiken voor tokencaching. Zie Tokencache voor een web-app of web-API voor meer informatie.
app.UseInMemoryTokenCaches(); // or a distributed token cache.
MsalUiRequiredException verwerken
Wanneer uw controller probeert geruisloos een token te verkrijgen voor verschillende scopes/resources, kan MSAL.NET zoals verwacht een MsalUiRequiredException veroorzaken als de gebruiker zich opnieuw moet aanmelden, of als voor toegang tot de resource meer claims vereist zijn (vanwege een beleid voor voorwaardelijke toegang). Zie voor meer informatie over beperking hoe u fouten en uitzonderingen in MSAL.NET afhandelt.
Meer informatie over web-apps die web-API's aanroepen en hoe deze worden geïmplementeerd met MSAL.NET of Microsoft. Identity.Web in nieuwe toepassingen.
MSAL-voordelen
Belangrijke voordelen van MSAL.NET voor uw app zijn:
Flexibiliteit. MSAL.NET helpt uw app tolerant te maken via:
- Microsoft Entra ID CCS-voordelen (Cached Credential Service). CCS werkt als een Microsoft Entra back-up.
- Proactieve verlenging van tokens als de API die u aanroept, tokens met een lange levensduur mogelijk maakt via continue toegangsevaluatie.
Beveiliging. U kunt PoP-tokens (Proof of Possession) verkrijgen als de web-API die u wilt aanroepen, dit vereist. Zie Bewijs van bezit in MSAL.NET voor meer informatie
Prestaties en schaalbaarheid. Als u uw cache niet hoeft te delen met ADAL.NET schakelt u de compatibiliteit van de verouderde cache uit wanneer u de vertrouwelijke clienttoepassing maakt (.WithLegacyCacheCompatibility(false)) om de prestaties aanzienlijk te verbeteren.
app = ConfidentialClientApplicationBuilder.Create(ClientId)
.WithCertificate(certificate)
.WithAuthority(authority)
.WithLegacyCacheCompatibility(false)
.Build();
Troubleshooting
MsalServiceException
De volgende informatie over probleemoplossing maakt twee aannames:
- Uw ADAL.NET code werkte.
- U bent gemigreerd naar MSAL door dezelfde client-id te behouden.
Als u een foutmelding krijgt met een van de volgende berichten:
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.
Los de uitzondering op met behulp van deze stappen:
- Controleer of u de nieuwste versie van MSAL.NET gebruikt.
- Controleer of de instantiehost die u hebt ingesteld bij het bouwen van de vertrouwelijke client-app en de instantiehost die u met ADAL hebt gebruikt, vergelijkbaar zijn. Is het met name dezelfde cloud (Azure Government, Microsoft Azure beheerd door 21Vianet of Azure Duitsland)?
MsalClientException
Geef in apps met meerdere tenants een algemene instantie op bij het bouwen van de app om een specifieke tenant te targeten, zoals de tenant van de gebruiker bij het aanroepen van een web-API. Sinds MSAL.NET 4.37.0 kunt u, wanneer u .WithAzureRegion opgeeft bij het maken van de toepassing, de Authority tijdens tokenaanvragen niet langer opgeven met .WithAuthority. Als u dit doet, krijgt u de volgende foutmelding bij het bijwerken van eerdere versies van 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."
Om dit probleem op te lossen, vervangt u .WithAuthority in de AcquireTokenXXX-expressie door .WithTenantId. Geef de tenant op met behulp van een GUID of een domeinnaam.
Volgende stappen
Meer informatie over: