Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Om du använder ASP.NET Core eller ASP.NET klassisk
Om du skapar ett webb-API ovanpå ASP.NET Core eller ASP.NET klassiskt rekommenderar vi att du använder Microsoft.Identity.Web. Se Webb-API:er med Microsoft.Identity.Web.
Kontrollera beslutsträdet: Är MSAL.NET rätt för mig?
Hämta token för en användares räkning
Scenario
- En klient (webbplats, skrivbord, mobilt, ensidesprogram) – som inte visas i bilden nedan – anropar ett skyddat webb-API som tillhandahåller en JWT-ägartoken i HTTP-huvudet "Authorization".
- Det skyddade webb-API:et verifierar den inkommande användartoken och använder MSAL.NET
AcquireTokenOnBehalfOfmetod för att begära från Microsoft Entra en annan token så att den kan anropa ett annat webb-API, till exempel Graph, med namnet underordnat webb-API, för användarens räkning.
Det här flödet, med namnet On-Behalf-Of flow (OBO), illustreras av den övre delen av bilden nedan. Den nedre delen är ett daemonscenario, även möjligt för webb-API:er.
Så här anropar du OBO
OBO-anropet görs genom att anropa AcquireTokenOnBehalfOf(IEnumerable<String>, UserAssertion) metoden i IConfidentialClientApplication gränssnittet.
Det här anropet söker i cachen av sig självt, så du behöver inte anropa AcquireTokenSilent, och det lagrar inte uppdateringstoken.
För scenarier där kontinuerlig åtkomst behövs utan en försäkran, se OBO för långlivade processer
Observera: Se till att skicka en åtkomsttoken, inte en ID-token, till
AcquireTokenOnBehalfOfmetoden. Syftet med en ID-token är en bekräftelse på att en användare har autentiserats och innehåller viss användarrelaterad information. Däremot avgör en åtkomsttoken om en användare har åtkomst till en resurs, vilket är mer lämpligt i det här On-Behalf-Of-scenariot. MSAL fokuserar på att erhålla giltiga åtkomsttoken. ID-token hämtas också och cachelagras, men deras förfallodatum spåras inte. Så en ID-token kan upphöra att gälla ochAcquireTokenSilentuppdaterar den inte.
private async Task AddAccountToCacheFromJwt(IEnumerable<string> scopes, JwtSecurityToken jwtToken, ClaimsPrincipal principal, HttpContext httpContext)
{
if (jwtToken == null)
{
throw new ArgumentOutOfRangeException("tokenValidationContext.SecurityToken should be a JWT Token");
}
UserAssertion userAssertion = new UserAssertion(jwtToken.RawData, "urn:ietf:params:oauth:grant-type:jwt-bearer");
IEnumerable<string> requestedScopes = scopes ?? jwtToken.Audiences.Select(a => $"{a}/.default");
// Create the application
var application = BuildConfidentialClientApplication(httpContext, principal);
// await to make sure that the cache is filled in before the controller tries to get access tokens
var result = await application.AcquireTokenOnBehalfOf(requestedScopes, userAssertion).ExecuteAsync();
}
Viktig anmärkning om On-Behalf-Of-flödet (OBO) med gästanvändare
När du utför OBO-flödet (On-Behalf-Of), särskilt med gästanvändare, är det viktigt att rikta sig mot den specifika klientorganisationen, som anges av claimet tid i klienttokenet. Använd inte /common eller /organizations i OBO, eftersom tokenen kommer att vara för användarens hemklientorganisation.
Korrekt användningsmönster
-
Extrahera
tid-claimet från klientens assertion-token: Detta identifierar den specifika klientorganisationen. -
Använd den klientorganisationsspecifika auktoriteten: Skapa auktoritets-URL:en med det extraherade
tid-anspråket.
Felaktigt mönster
Många implementeringar använder felaktigt slutpunkten /common för att utföra OBO. Den här metoden rekommenderas inte och kan leda till problem, särskilt med gästanvändare.
Hantering av multifaktorautentisering (MFA), villkorlig åtkomst och inkrementellt medgivande
Scenario för misslyckande
Det är ett vanligt scenario att en klientadministratör begränsar åtkomsten till det underordnade API:et (till exempel graph) genom att kräva att slutanvändarna slutför en MFA-utmaning (Multi-Factor Authentication). De använder dock ofta inte samma begränsningar för webb-API:et.
- Klienten (t.ex. skrivbordsapp eller webbplats) ber om en token för webb-API:et. MFA tillämpas inte just nu.
- Webb-API:t försöker byta den här tokenen mot en token för nedströms webb-API:t (t.ex. Graph) via on-behalf-of-flödet. Detta misslyckas eftersom åtkomst via Graph kräver att användaren har slutfört MFA-utmaningen. Anropet till
AcquireTokenOnBehalfOfmisslyckas med ettMsalUiRequiredExceptionsom också harClaimsegenskapen inställd.
Så här signalerar du att MFA behövs till klienten
Webb-API:t behöver skicka tillbaka undantaget till klienten med strängen med anspråk.
Standardmönstret för att signalera det här felet till en klient är att svara med HTTP 401 och med en WWW-Authenticate rubrik som kapslar in information om felet.
Webb-API:et svarar med 401 + WWW-Authenticate
// This example is for an ASP.NET Core web API
public void ReplyUnauthorizedWithWwwAuthenticateHeader(MsalUiRequiredException ex)
{
httpResponse.StatusCode = (int)HttpStatusCode.Unauthorized; // HTTP 401
httpResponse.Headers[HeaderNames.WWWAuthenticate] = $"Bearer claims={ex.Claims}, error={ex.Message}";
}
Hantera felet på klientsidan
Klienten måste tolka 401 meddelanden och parsa WWW-Authenticate rubriker. MSAL.NET erbjuder parsning av API:er:
// assuming an HttpResponseMessage response with StatusCode=HttpStatusCode.Unauthorized
WwwAuthenticateParameters wwwParams = WwwAuthenticateParameters.CreateFromAuthenticationHeaders(response.HttpResponseHeaders, "Bearer");
string claims = wwwParams.Claims; // you may also extract other parameters such as Error and Authority
// desktop or mobile app
app.AcquireTokenInteractive(scopes).WithClaims(wwwParams.Claims);
// web app - redirect to the login page and add the claims to the authorization URL
RedirectToLogin(wwwParams.ConsentUri);
Långvariga OBO-processer
Ett OBO-scenario är när ett webb-API kör långvariga processer åt användaren (till exempel OneDrive som skapar album åt dig). Detta kan implementeras så här:
- Innan du påbörjar en långvarig process, anropa:
string sessionKey = // custom key or null
var authResult = await ((ILongRunningWebApi)confidentialClientApp)
.InitiateLongRunningProcessInWebApi(
scopes,
userAccessToken,
ref sessionKey)
.ExecuteAsync();
userAccessToken är en användaråtkomsttoken som används för att anropa det här webb-API:et.
sessionKey används som en nyckel vid cachelagring och hämtning av OBO-token. Om den är inställd på null, anger MSAL det till assertionshashen för den angivna användartoken. Det kan också ställas in av utvecklaren på något som identifierar en specifik användarsession, till exempel det valfria sid anspråket från användartoken (mer information finns i Ange valfria anspråk till din app).
InitiateLongRunningProcessInWebApikontrollerar inte cachen. den använder användartoken för att hämta en ny OBO-token från Microsoft Entra ID, som sedan cachelagras och returneras.
- I den långvariga processen, när en OBO-token behövs, anropar du
AcquireTokenInLongRunningProcessenligt följande mönster:
try {
authResult = await ((ILongRunningWebApi)confidentialClientApp)
.AcquireTokenInLongRunningProcess(
scopes,
sessionKey)
.ExecuteAsync();
}
catch (MsalClientException ex) {
// No tokens were found with this cache key.
// First call InitiateLongRunningProcessInWebApi with a valid user assertion
// to acquire tokens from Microsoft Entra ID and cache them.
if (ex.ErrorCode == MsalError.OboCacheKeyNotInCacheError)
{
authResult = await ((ILongRunningWebApi)confidentialClientApp)
.InitiateLongRunningProcessInWebApi(
scopes,
userAccessToken, // Valid access token
ref sessionKey)
.ExecuteAsync();
}
} catch (MsalUiRequiredException ex) {
// A refresh token was used to acquire new tokens
// but Microsoft Entra ID requires the user to sign in again.
// Trigger your app's user sign-in again by replying with a 401 + WWW-Authenticate
// Then call InitiateLongRunningProcessInWebApi once a new access token is acquired from the user
httpResponse.StatusCode = (int)HttpStatusCode.Unauthorized;
httpResponse.Headers[HeaderNames.WWWAuthenticate] = $"Bearer claims={ex.Claims}, error={ex.Message}";
}
Skicka sessionKey, som är associerat med den aktuella användarsessionen och kommer att användas för att hämta den relaterade OBO-tokenen. Om tokenen har upphört att gälla använder MSAL den cachelagrade uppdateringstoken för att hämta en ny OBO-åtkomsttoken från Microsoft Entra ID och cachelagra den. Om ingen token hittas med detta sessionKeygenererar MSAL en MsalClientException eller en MsalUiRequiredException. Se till att hämta en giltig användartoken och anropa InitiateLongRunningProcessInWebApi om så är fallet.
Cacheutmatning för långvariga OBO-processer
Vi rekommenderar starkt att du använder en distribuerad bevarad cache i ett webb-API-scenario. Eftersom dessa API:er lagrar uppdateringstoken föreslår MSAL inte någon förfallotid eftersom uppdateringstoken har en lång livslängd och kan användas om och om igen.
Vi rekommenderar att du anger borttagningsprinciper för L1 och L2 manuellt, till exempel en maxstorlek för L1-cachen och en glidande förfallotid för L2.
Hantering av undantag
Om ett AcquireTokenInLongRunningProcess undantag uppstår när det inte går att hitta en token och L2-cachen har en cachepost för samma cachenyckel kontrollerar du att L2-cacheläsningsåtgärden har slutförts.
AcquireTokenInLongRunningProcess skiljer sig från InitiateLongRunningProcessInWebApi och AcquireTokenOnBehalfOf på så sätt att om cacheläsningen misslyckas kan den här metoden inte hämta en ny token från Microsoft Entra ID, eftersom den inte har något ursprungligt användarintyg. Om du använder Microsoft. Identity.Web.TokenCache för att aktivera distribuerad cache anger du OnL2CacheFailure-händelsen för att försöka utföra L2-anropet igen och/eller lägga till extra loggar, som kan aktiveras via inbyggda MSAL-funktioner.
Ta bort konton
Från och med MSAL 4.51.0 kan du ta bort cachelagrade token genom att anropa StopLongRunningProcessInWebApiAsync och skicka med en cachenyckel. I tidigare versioner av MSAL rekommenderas att använda utrensningsprinciper för L2-cache. Om omedelbar borttagning krävs tar du bort den L2-cachenod som är associerad med sessionKey.
Troubleshooting
Om du uppdaterar MSAL.NET till 4.51.0+ finns det en risk att InitiateLongRunningProcessInWebApi slutar returnera token och utlöser ett undantag om du förlitar dig på att den ska returnera token när den långvariga processen redan har startats och det finns en token i cachen för den angivna cachenyckeln.
InitiateLongRunningProcessInWebApi inspekterar inte längre cachen för att hämta token. Använd AcquireTokenInLongRunningProcess för att fortsätta få åtkomst till den långvariga process som för närvarande är aktiv.
InitiateLongRunningProcessInWebApi Ska endast användas för att initiera processen. Om det inte går att göra dessa ändringar snabbt och du uppdaterar till MSAL 4.54.1 eller senare kan du använda InitiateLongRunningProcessInWebApi().WithSearchInCacheForLongRunningProcess() för att återställa beteendet för InitiateLongRunningProcessInWebApi
Ändringar i appregistrering
Webb-API:er definierar behörighetsomfång. Mer information finns i Snabbstart: Konfigurera ett program för att exponera webb-API:er (förhandsversion).
Webb-API:er bestämmer vilken version av token de vill acceptera. För ditt eget webb-API kan du ändra egenskapen i manifestet med namnet
accessTokenAcceptedVersion(till1eller2). Om du inte uttryckligen vet att du behöver version1väljer du2alltid . Mer information finns i Microsoft Entra appmanifest.
Praktisk användning av OBO i ett ASP.NET/ASP.NET Core program
Om du skapar ett webb-API ovanpå ASP.NET Core rekommenderar vi att du använder Microsoft.Identity.Web. Se webb-API:er med Microsoft.Identity.Web.
I ett ASP.NET/ASP.NET Core-webb-API anropas OBO vanligtvis för OnTokenValidated händelsen JwtBearerOptions. Token används sedan inte omedelbart, men det här anropet har effekten att fylla i cacheminnet för användartoken. Senare kommer styrenheterna att anropa AcquireTokenSilent, vilket innebär att cachen används, att åtkomsttoken uppdateras vid behov eller att en ny hämtas för en ny resurs, men fortfarande för samma användare.
Så här händer när en JWT-ägartoken tas emot och verifieras av webb-API:et:
public static IServiceCollection AddProtectedApiCallsWebApis(this IServiceCollection services, IConfiguration configuration, IEnumerable<string> scopes)
{
...
services.Configure<JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme, options =>
{
options.Events.OnTokenValidated = async context =>
{
var tokenAcquisition = context.HttpContext.RequestServices.GetRequiredService<ITokenAcquisition>();
context.Success();
// Adds the token to the cache, and also handles the incremental consent and claim challenges
tokenAcquisition.AddAccountToCacheFromJwt(context, scopes);
await Task.FromResult(0);
};
});
return services;
}
Och här är koden i åtgärderna för API-kontrollanterna, som anropar underordnade API:er:
private async Task GetTodoList(bool isAppStarting)
{
...
//
// Get an access token to call the To Do service.
//
AuthenticationResult result = null;
try
{
result = await _app.AcquireTokenSilent(Scopes, accounts.FirstOrDefault())
.ExecuteAsync()
.ConfigureAwait(false);
}
...
// Once the token has been returned by MSAL, add it to the http authorization header, before making the call to access the To Do list service.
// Make sure to use an access token and not an ID token
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
// Call the To Do list service.
HttpResponseMessage response = await _httpClient.GetAsync(TodoListBaseAddress + "/api/todolist");
...
}
Metoden GetAccountIdentifier använder anspråken som är associerade med identiteten för den användare som webb-API:et tog emot JWT för:
public static string GetMsalAccountId(this ClaimsPrincipal claimsPrincipal)
{
string userObjectId = GetObjectId(claimsPrincipal);
string tenantId = GetTenantId(claimsPrincipal);
if (!string.IsNullOrWhiteSpace(userObjectId) && !string.IsNullOrWhiteSpace(tenantId))
{
return $"{userObjectId}.{tenantId}";
}
return null;
}
Protokoll
Mer information om on-Behalf-Of-protokollet finns i Azure Active Directory v2.0 och OAuth 2.0 On-Behalf-Of flow.
Exempel som illustrerar flödets räkning
| Sample | Platform | Description |
|---|---|---|
| active-directory-aspnetcore-webapi-tutorial-v2 | ASP.NET Core 2.2 Web API, Desktop (WPF) | ASP.NET Core 2.1 Web API anropar Microsoft Graph, som anropas från ett WPF-program med hjälp av Azure AD v2 ![]() |
