Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Hinweis
Dies ist nicht die neueste Version dieses Artikels. Die aktuelle Version finden Sie in der .NET 10-Version dieses Artikels.
Warnung
Diese Version von ASP.NET Core wird nicht mehr unterstützt. Weitere Informationen finden Sie in der .NET- und .NET Core-Supportrichtlinie. Die aktuelle Version finden Sie in der .NET 9-Version dieses Artikels.
In diesem Artikel wird erläutert, wie Sie Blazor serverseitig für zusätzliche Sicherheitsszenarios konfigurieren, einschließlich der Tokenübergabe an eine Blazor-App.
Hinweis
Die Codebeispiele in diesem Artikel verwenden Nullwerte zulassende Verweistypen (Nullable Reference Types, NRTs) und die statische Analyse des NULL-Zustands des .NET-Compilers, die in ASP.NET Core in .NET 6 oder höher unterstützt werden. Entfernen Sie beim Targeting von .NET 5 oder einer früheren Version die Nulltypbezeichnung (?) aus den string?, TodoItem[]?, WeatherForecast[]? und IEnumerable<GitHubBranch>?-Typen in den Beispielen des Artikels.
Übergeben von Token an eine serverseitige Blazor-App
Dieser Abschnitt gilt für Blazor Web Apps. Blazor ServerSehen Sie sich die .NET 7-Version dieses Artikels an.
Wenn Sie lediglich Zugriffstoken verwenden möchten, um Web-API-Aufrufe von einem Blazor Web Appmit einem benannten HTTP-Client auszuführen, lesen Sie den Abschnitt "Verwenden eines Tokenhandlers für Web-API-Aufrufe ", in dem erläutert wird, wie Sie mithilfe einer DelegatingHandler Implementierung das Zugriffstoken eines Benutzers an ausgehende Anforderungen anfügen. Die folgende Anleitung in diesem Abschnitt richtet sich an Entwickler, die Zugriffstoken, Aktualisierungstoken und andere serverseitige Authentifizierungseigenschaften benötigen.
Um Token und andere Authentifizierungseigenschaften für die serverseitige Verwendung in Blazor Web Apps zu speichern, empfehlen wir die Verwendung IHttpContextAccessor/HttpContext (IHttpContextAccessor, HttpContext). Das Lesen von Token aus HttpContext, einschließlich als kaskadierender Parameter, wird unterstützt, um Token für die Verwendung während des interaktiven Serverrenderings zu erhalten, wenn die Token während des statischen serverseitigen Renderings (statisches SSR) oder des Vorrenderings abgerufen werden. Token werden jedoch nicht aktualisiert, wenn sich der Benutzer authentifiziert, nachdem der Schaltkreis eingerichtet wurde, da das HttpContext Token zu Beginn der SignalR Verbindung erfasst wird. Außerdem bedeutet die Verwendung von AsyncLocal<T> durch IHttpContextAccessor, dass Sie darauf achten müssen, den Ausführungskontext nicht zu verlieren, bevor Sie HttpContext lesen. Weitere Informationen finden Sie unter IHttpContextAccessor/HttpContext in ASP.NET Core Blazor Apps.
Rufen Sie in einer Dienstklasse Zugriff auf die Mitglieder des Namespaces Microsoft.AspNetCore.Authentication ab, um die GetTokenAsync Methode auf HttpContext bereitzustellen. Ein alternativer Ansatz, der im folgenden Beispiel auskommentiert ist, besteht darin, AuthenticateAsync auf HttpContext aufzurufen. Für den zurückgegebenen AuthenticateResult.Properties rufen Sie GetTokenValue auf.
using Microsoft.AspNetCore.Authentication;
public class AuthenticationProcessor(IHttpContextAccessor httpContextAccessor)
{
public async Task<string?> GetAccessToken()
{
if (httpContextAccessor.HttpContext is null)
{
throw new Exception("HttpContext not available");
}
// Approach 1: Call 'GetTokenAsync'
var accessToken = await httpContextAccessor.HttpContext
.GetTokenAsync("access_token");
// Approach 2: Authenticate the user and call 'GetTokenValue'
/*
var authResult = await httpContextAccessor.HttpContext.AuthenticateAsync();
var accessToken = authResult?.Properties?.GetTokenValue("access_token");
*/
return accessToken;
}
}
Der Dienst wird in der Datei des Serverprojekts Program registriert:
builder.Services.AddScoped<AuthenticationProcessor>();
AuthenticationProcessor kann in serverseitige Dienste eingefügt werden, z. B. in einer DelegatingHandler für eine vorkonfigurierte HttpClient. Das folgende Beispiel dient nur zu Demonstrationszwecken oder für den Fall, dass Sie eine spezielle Verarbeitung im AuthenticationProcessor Dienst ausführen müssen, da Sie das Token einfach direkt zum Aufrufen externer Web-APIs einfügen IHttpContextAccessor und abrufen können (weitere Informationen zur direkten Verwendung IHttpContextAccessor von Web-APIs finden Sie im Abschnitt "Verwenden eines Tokenhandlers für Web-API-Aufrufe ").
using System.Net.Http.Headers;
public class TokenHandler(AuthenticationProcessor authProcessor) :
DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
var accessToken = authProcessor.GetAccessToken();
request.Headers.Authorization =
new AuthenticationHeaderValue("Bearer", accessToken);
return await base.SendAsync(request, cancellationToken);
}
}
Der Tokenhandler wird registriert und fungiert als delegierender Handler für einen benannten HTTP-Client in der Program Datei:
builder.Services.AddHttpContextAccessor();
builder.Services.AddScoped<TokenHandler>();
builder.Services.AddHttpClient("ExternalApi",
client => client.BaseAddress = new Uri(builder.Configuration["ExternalApiUri"] ??
throw new Exception("Missing base address!")))
.AddHttpMessageHandler<TokenHandler>();
Vorsicht
Stellen Sie sicher, dass Token niemals vom Client (dem .Client Projekt) übertragen und verarbeitet werden, z. B. in einer Komponente, die interaktives Autorendering verwendet und auf dem Client oder von einem clientseitigen Dienst gerendert wird. Sorgen Sie dafür, dass der Client immer den Server (Projekt) aufruft, um Anforderungen mit Authentifizierungstoken zu verarbeiten.
Token und andere Authentifizierungsdaten sollten niemals den Server verlassen.
Interaktive Auto-Komponenten finden Sie unter ASP.NET Core-Authentifizierung Blazor und -Autorisierung, die zeigt, wie Zugriffstoken und andere Authentifizierungseigenschaften auf dem Server beibehalten werden. Erwägen Sie außerdem die Übernahme des Backend-for-Frontend (BFF)-Musters, das eine ähnliche Aufrufstruktur übernimmt und im Abschnitt Blazor Web App für OIDC-Anbieter sowie in ASP.NET Core mit Microsoft Entra ID absichern für Microsoft Blazor Web App Web mit Entra beschrieben wird.
Verwenden eines Tokenhandlers für Web-API-Aufrufe
Der folgende Ansatz zielt darauf ab, das Zugriffstoken eines Benutzers an ausgehende Anforderungen anzufügen, insbesondere um Web-API-Aufrufe an externe Web-API-Apps zu senden. Der Ansatz wird für ein Blazor Web App globales interaktives Server-Rendering gezeigt, aber der gleiche allgemeine Ansatz gilt für Blazor Web Apps, die den globalen interaktiven automatischen Rendermodus übernehmen. Das wichtige Konzept, das zu beachten ist, besteht darin, dass der Zugriff auf die HttpContext mithilfe von IHttpContextAccessor nur auf dem Server ausgeführt wird.
Für eine Demonstration der Anleitung in diesem Abschnitt, sehen Sie sich die BlazorWebAppOidcBlazorWebAppOidcServer Beispielanwendungen (.NET 8 oder höher) im Blazor Beispiel-GitHub-Repository an. Die Beispiele übernehmen einen globalen interaktiven Rendermodus und die OIDC-Authentifizierung mit Microsoft Entra, ohne entra-spezifische Pakete zu verwenden. In den Beispielen wird veranschaulicht, wie ein JWT-Zugriffstoken übergeben wird, um eine sichere Web-API aufzurufen.
Microsoft Identity Platform mit Microsoft Identity Web packages für Microsoft Entra ID bietet eine API zum Aufrufen von Web-APIs von Blazor Web Apps mit automatischer Tokenverwaltung und -erneuerung. Weitere Informationen finden Sie unter Sichern einer ASP.NET Core Blazor Web App mit Microsoft Entra ID und die BlazorWebAppEntra und BlazorWebAppEntraBff Beispiel-Apps (.NET 9 oder später) im Blazor Samples GitHub-Repository.
Verwenden Sie die Subklasse DelegatingHandler, um das Zugriffstoken eines Benutzers an ausgehende Anfragen anzuhängen. Der Tokenhandler wird nur auf dem Server ausgeführt, daher ist die Verwendung HttpContext sicher.
TokenHandler.cs:
using System.Net.Http.Headers;
using Microsoft.AspNetCore.Authentication;
public class TokenHandler(IHttpContextAccessor httpContextAccessor) :
DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
if (httpContextAccessor.HttpContext is null)
{
throw new Exception("HttpContext not available");
}
var accessToken = await httpContextAccessor.HttpContext.GetTokenAsync("access_token");
if (accessToken is null)
{
throw new Exception("No access token");
}
request.Headers.Authorization =
new AuthenticationHeaderValue("Bearer", accessToken);
return await base.SendAsync(request, cancellationToken);
}
}
Hinweis
Anleitung zum Zugriff auf ein AuthenticationStateProvider von einem DelegatingHandler, finden Sie im Abschnitt „Access AuthenticationStateProvider in outgoing request middleware“ .
In der Datei des Program Projekts wird der Tokenhandler (TokenHandler) als bereichsbezogener Dienst registriert und als Nachrichtenhandler des benannten HTTP-Clients mit AddHttpMessageHandlerangegeben.
Im folgenden Beispiel ist der {HTTP CLIENT NAME} Platzhalter der Name des HttpClient, und der {BASE ADDRESS} Platzhalter ist der Basisadressen-URI der Web-API. Weitere Informationen zu AddHttpContextAccessor finden Sie unter IHttpContextAccessor/HttpContext in ASP.NET Core-AnwendungenBlazor.
In Program.cs:
builder.Services.AddHttpContextAccessor();
builder.Services.AddScoped<TokenHandler>();
builder.Services.AddHttpClient("{HTTP CLIENT NAME}",
client => client.BaseAddress = new Uri("{BASE ADDRESS}"))
.AddHttpMessageHandler<TokenHandler>();
Beispiel:
builder.Services.AddScoped<TokenHandler>();
builder.Services.AddHttpClient("ExternalApi",
client => client.BaseAddress = new Uri("https://localhost:7277"))
.AddHttpMessageHandler<TokenHandler>();
Sie können die HTTP-Clientbasisadresse aus der Konfiguration mit builder.Configuration["{CONFIGURATION KEY}"] angeben, wobei der Platzhalter der {CONFIGURATION KEY}Konfigurationsschlüssel ist.
new Uri(builder.Configuration["ExternalApiUri"] ?? throw new IOException("No URI!"))
Geben Sie in appsettings.json das ExternalApiUri an. Im folgenden Beispiel wird der Wert auf die localhost-Adresse der externen Web-API gesetzt: https://localhost:7277
"ExternalApiUri": "https://localhost:7277"
Zu diesem Zeitpunkt kann eine HttpClient von einer Komponente erstellte Komponente sichere Web-API-Anforderungen erstellen. Im folgenden Beispiel ist {REQUEST URI} der zugehörige Anforderungs-URI, und der {HTTP CLIENT NAME} Platzhalter ist der Name des HttpClient:
using var request = new HttpRequestMessage(HttpMethod.Get, "{REQUEST URI}");
var client = ClientFactory.CreateClient("{HTTP CLIENT NAME}");
using var response = await client.SendAsync(request);
Beispiel:
using var request = new HttpRequestMessage(HttpMethod.Get, "/weather-forecast");
var client = ClientFactory.CreateClient("ExternalApi");
using var response = await client.SendAsync(request);
Zusätzliche Features sind geplant Blazor, die von Access AuthenticationStateProvider in der Middleware für ausgehende Anforderungen (dotnet/aspnetcore #52379) nachverfolgt werden.
Problem beim Bereitstellen von Zugriffstoken für HttpClient im interaktiven Servermodus (dotnet/aspnetcore #52390) ist ein geschlossenes Problem, das hilfreiche Diskussions- und potenzielle Problemumgehungsstrategien für erweiterte Anwendungsfälle enthält.
Token, die außerhalb der Razor-Komponenten in einer serverseitigen Blazor-App verfügbar sind, können mit dem in diesem Abschnitt beschriebenen Ansatz an Komponenten übergeben werden. Das Beispiel in diesem Abschnitt konzentriert sich auf die Übergabe, von Zugriffstoken, Aktualisierungstoken und Anforderungsfälschungssicherheits-Token (XSRF) an die Blazor-App, aber der Ansatz ist auch für andere HTTP-Kontextzustände gültig.
Hinweis
Das Übergeben des XSRF-Tokens an Razor-Komponenten ist in Szenarien nützlich, in denen Komponenten an Identity oder andere Endpunkte POSTEN, die eine Überprüfung erfordern. Wenn Ihre App nur Zugriffs- und Aktualisierungstoken erfordert, können Sie den XSRF-Tokencode aus dem folgenden Beispiel entfernen.
Authentifizieren Sie die App genauso wie eine reguläre Razor Pages- oder MVC-App. Stellen Sie die Token für das Authentifizierungscookie bereit, und speichern Sie diese.
In der Program-Datei:
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
...
builder.Services.Configure<OpenIdConnectOptions>(
OpenIdConnectDefaults.AuthenticationScheme, options =>
{
options.ResponseType = OpenIdConnectResponseType.Code;
options.SaveTokens = true;
options.Scope.Add(OpenIdConnectScope.OfflineAccess);
});
In Startup.cs:
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
...
services.Configure<OpenIdConnectOptions>(
OpenIdConnectDefaults.AuthenticationScheme, options =>
{
options.ResponseType = OpenIdConnectResponseType.Code;
options.SaveTokens = true;
options.Scope.Add(OpenIdConnectScope.OfflineAccess);
});
In Startup.cs:
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
...
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
options.ResponseType = OpenIdConnectResponseType.Code;
options.SaveTokens = true;
options.Scope.Add(OpenIdConnectScope.OfflineAccess);
});
Optional werden zusätzliche Bereiche mit options.Scope.Add("{SCOPE}"); hinzugefügt, wobei der Platzhalter {SCOPE} der zusätzliche hinzuzufügende Bereich ist.
Definieren Sie einen bereichsbezogenen Tokenanbieterdienst, der innerhalb der Blazor-App verwendet werden kann, um die Token aus der Abhängigkeitsinjektion (Dependency Injection, DI) aufzulösen.
TokenProvider.cs:
public class TokenProvider
{
public string? AccessToken { get; set; }
public string? RefreshToken { get; set; }
public string? XsrfToken { get; set; }
}
Fügen Sie in der Program-Datei Dienste für Folgendes hinzu:
-
IHttpClientFactory: Wird in einer
WeatherForecastService-Klasse verwendet, die Wetterdaten von einer Server-API mit einem Zugriffstoken abruft. -
TokenProvider: Enthält die Zugriffs- und Aktualisierungstoken.
builder.Services.AddHttpClient();
builder.Services.AddScoped<TokenProvider>();
Fügen Sie in Startup.ConfigureServices von Startup.cs Dienste für Folgendes hinzu:
-
IHttpClientFactory: Wird in einer
WeatherForecastService-Klasse verwendet, die Wetterdaten von einer Server-API mit einem Zugriffstoken abruft. -
TokenProvider: Enthält die Zugriffs- und Aktualisierungstoken.
services.AddHttpClient();
services.AddScoped<TokenProvider>();
Definieren Sie eine Klasse, um den anfänglichen App-Zustand mit den Zugriffs- und Aktualisierungstoken zu übergeben.
InitialApplicationState.cs:
public class InitialApplicationState
{
public string? AccessToken { get; set; }
public string? RefreshToken { get; set; }
public string? XsrfToken { get; set; }
}
Erstellen Sie in der Datei Pages/_Host.cshtml eine Instanz von InitialApplicationState, und übergeben Sie diese als Parameter an die App:
Erstellen Sie in der Datei Pages/_Layout.cshtml eine Instanz von InitialApplicationState, und übergeben Sie diese als Parameter an die App:
Erstellen Sie in der Datei Pages/_Host.cshtml eine Instanz von InitialApplicationState, und übergeben Sie diese als Parameter an die App:
@using Microsoft.AspNetCore.Authentication
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
...
@{
var tokens = new InitialApplicationState
{
AccessToken = await HttpContext.GetTokenAsync("access_token"),
RefreshToken = await HttpContext.GetTokenAsync("refresh_token"),
XsrfToken = Xsrf.GetAndStoreTokens(HttpContext).RequestToken
};
}
<component ... param-InitialState="tokens" ... />
Lösen Sie in der App-Komponente (App.razor) den Dienst auf, und initialisieren Sie diesen mit den Daten aus dem Parameter:
@inject TokenProvider TokenProvider
...
@code {
[Parameter]
public InitialApplicationState? InitialState { get; set; }
protected override Task OnInitializedAsync()
{
TokenProvider.AccessToken = InitialState?.AccessToken;
TokenProvider.RefreshToken = InitialState?.RefreshToken;
TokenProvider.XsrfToken = InitialState?.XsrfToken;
return base.OnInitializedAsync();
}
}
Hinweis
Eine Alternative zum Zuweisen des Anfangszustands zum TokenProvider im vorherigen Beispiel besteht darin, die Daten in einen bereichsbezogenen Dienst innerhalb von OnInitializedAsync für Verwendung in der App zu kopieren.
Fügen Sie der App einen Paketverweis für das NuGet-Paket Microsoft.AspNet.WebApi.Client hinzu.
Hinweis
Eine Anleitung zum Hinzufügen von Paketen zu .NET-Anwendungen finden Sie in den Artikeln unter Pakete installieren und verwalten unter Workflow für die Paketnutzung (NuGet-Dokumentation). Überprüfen Sie unter NuGet.org, ob die richtige Paketversion verwendet wird.
Fügen Sie den Tokenanbieter in den Dienst ein, der eine sichere API-Anforderung stellt, und rufen Sie das Token für die API-Anforderung ab:
WeatherForecastService.cs:
using System;
using System.Net.Http;
using System.Threading.Tasks;
public class WeatherForecastService
{
private readonly HttpClient http;
private readonly TokenProvider tokenProvider;
public WeatherForecastService(IHttpClientFactory clientFactory,
TokenProvider tokenProvider)
{
http = clientFactory.CreateClient();
this.tokenProvider = tokenProvider;
}
public async Task<WeatherForecast[]> GetForecastAsync()
{
var token = tokenProvider.AccessToken;
using var request = new HttpRequestMessage(HttpMethod.Get,
"https://localhost:5003/WeatherForecast");
request.Headers.Add("Authorization", $"Bearer {token}");
using var response = await http.SendAsync(request);
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<WeatherForecast[]>() ??
Array.Empty<WeatherForecast>();
}
}
Fügen Sie für ein XSRF-Token, das an eine Komponente übergeben wird, den TokenProvider ein, und fügen Sie das XSRF-Token der POST-Anforderung hinzu. Im folgenden Beispiel wird das Token einem Abmeldeendpunkt- POST hinzugefügt. Das Szenario für das folgende Beispiel ist, dass der Abmeldeendpunkt (Areas/Identity/Pages/Account/Logout.cshtml, in die App eingefügt) keinen IgnoreAntiforgeryTokenAttribute (@attribute [IgnoreAntiforgeryToken]) angibt, da er zusätzlich zu einem normalen Abmeldevorgang, der geschützt werden muss, eine Aktion ausführt. Der Endpunkt erfordert ein gültiges XSRF-Token, um die Anforderung erfolgreich verarbeiten zu können.
In einer Komponente, die autorisierten Benutzern eine Abmeldeschaltfläche bietet:
@inject TokenProvider TokenProvider
...
<AuthorizeView>
<Authorized>
<form action="/Identity/Account/Logout?returnUrl=%2F" method="post">
<button class="nav-link btn btn-link" type="submit">Logout</button>
<input name="__RequestVerificationToken" type="hidden"
value="@TokenProvider.XsrfToken">
</form>
</Authorized>
<NotAuthorized>
...
</NotAuthorized>
</AuthorizeView>
Festlegen des Authentifizierungsschemas
Für eine App, die mehr als eine Authentifizierungsmiddleware verwendet und daher über mehr als ein Authentifizierungsschema verfügt, kann das von Blazor verwendete Schema explizit in der Endpunktkonfiguration der Program-Datei festgelegt werden. Im folgenden Beispiel wird das OpenID Connect-Schema (OIDC) festgelegt:
Für eine App, die mehr als eine Authentifizierungsmiddleware verwendet und daher über mehr als ein Authentifizierungsschema verfügt, kann das von Blazor verwendete Schema explizit in der Endpunktkonfiguration von Startup.cs festgelegt werden. Im folgenden Beispiel wird das OpenID Connect-Schema (OIDC) festgelegt:
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
...
app.MapRazorComponents<App>().RequireAuthorization(
new AuthorizeAttribute
{
AuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme
})
.AddInteractiveServerRenderMode();
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
...
app.MapBlazorHub().RequireAuthorization(
new AuthorizeAttribute
{
AuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme
});
Für eine App, die mehr als eine Authentifizierungsmiddleware verwendet und daher über mehr als ein Authentifizierungsschema verfügt, kann das von Blazor verwendete Schema explizit in der Endpunktkonfiguration von Startup.Configure festgelegt werden. Im folgenden Beispiel wird das Microsoft Entra ID-Schema festgelegt:
endpoints.MapBlazorHub().RequireAuthorization(
new AuthorizeAttribute
{
AuthenticationSchemes = AzureADDefaults.AuthenticationScheme
});
Verwenden von OpenID Connect v2.0-Endpunkten (OIDC)
In Versionen von ASP.NET Core vor .NET 5 verwenden die Authentifizierungsbibliothek und Blazor -vorlagen OpenID Connect (OIDC) v1.0-Endpunkte. Um einen Endpunkt v2.0 mit Versionen von ASP.NET Core vor .NET 5 zu verwenden, konfigurieren Sie die Option `OpenIdConnectOptions.Authority` unter `OpenIdConnectOptions`.
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme,
options =>
{
options.Authority += "/v2.0";
}
Alternativ kann die Einstellung in der Datei mit den App-Einstellungen (appsettings.json) festgelegt werden:
{
"AzureAd": {
"Authority": "https://login.microsoftonline.com/common/oauth2/v2.0",
...
}
}
Wenn das Anheften eines Segments an die Autorität für den OIDC-Anbieter der App nicht geeignet ist (z. B. bei Nicht-ME-ID-Anbietern), legen Sie die Authority-Eigenschaft direkt fest. Legen Sie die Eigenschaft entweder in OpenIdConnectOptions oder in der Datei mit den App-Einstellungen mit dem Authority-Schlüssel fest.
Codeänderungen
Die Liste der Ansprüche im ID-Token ändert sich für Endpunkte der Version 2.0. Microsoft-Dokumentation zu den Änderungen wurde eingestellt, aber Anleitungen zu den Ansprüchen in einem ID-Token sind im ID-Token-Anspruchsverweis verfügbar.
Da Ressourcen in Bereichs-URIs für 2.0-Endpunkte angegeben werden, entfernen Sie die Einstellung der OpenIdConnectOptions.Resource-Eigenschaft in OpenIdConnectOptions:
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options => { ... options.Resource = "..."; // REMOVE THIS LINE ... }
App-ID-URI
- Bei der Verwendung von v2.0-Endpunkten definieren APIs einen
App ID URI, der einen eindeutigen Bezeichner für die API darstellen soll. - Alle Bereiche enthalten den App-ID-URI als Präfix, und die v2.0-Endpunkte geben Zugriffstoken mit dem App-ID-URI als Zielgruppe aus.
- Bei Verwendung von v2.0-Endpunkten ändert sich die in der Server-API konfigurierte Client-ID von der API-Anwendungs-ID (Client-ID) in den App-ID-URI.
appsettings.json:
{
"AzureAd": {
...
"ClientId": "https://{TENANT}.onmicrosoft.com/{PROJECT NAME}"
...
}
}
Sie finden den zu verwendenden App-ID-URI in der Beschreibung zur App-Registrierung des OIDC-Anbieters.
Verbindungshandler zum Erfassen von Benutzern für benutzerdefinierte Dienste
Verwenden Sie einen CircuitHandler, um einen Benutzer aus dem AuthenticationStateProvider zu erfassen und den Benutzer in einem Dienst festzulegen. Wenn Sie den Benutzer bzw. die Benutzerin aktualisieren möchten, registrieren Sie einen Rückruf an AuthenticationStateChanged und stellen Sie einen Task in die Warteschlange, um die neue Person zu erhalten und den Dienst zu aktualisieren. Im folgenden Beispiel wird dieser Ansatz veranschaulicht.
Im folgenden Beispiel:
-
OnConnectionUpAsync wird jedes Mal aufgerufen, wenn die Verbindung wiederhergestellt wird, wobei der Benutzer für die Lebensdauer der Verbindung festgelegt wird. Nur die OnConnectionUpAsync-Methode ist erforderlich, es sei denn, Sie implementieren Updates über einen Handler für Authentifizierungsänderungen (
AuthenticationChangedim folgenden Beispiel). -
OnCircuitOpenedAsync wird aufgerufen, um den Handler für geänderte Authentifizierung (
AuthenticationChanged) anzufügen, um den Benutzer zu aktualisieren. - Der
catch-Block derUpdateAuthentication-Aufgabe reagiert nicht auf Ausnahmen, da es zu diesem Zeitpunkt der Codeausführung keine Möglichkeit gibt, die Ausnahmen zu melden. Wenn eine Ausnahme vom Task ausgelöst wird, wird die Ausnahme an anderer Stelle in der App gemeldet.
UserService.cs:
using System.Security.Claims;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Server.Circuits;
public class UserService
{
private ClaimsPrincipal currentUser = new(new ClaimsIdentity());
public ClaimsPrincipal GetUser() => currentUser;
internal void SetUser(ClaimsPrincipal user)
{
if (currentUser != user)
{
currentUser = user;
}
}
}
internal sealed class UserCircuitHandler(
AuthenticationStateProvider authenticationStateProvider,
UserService userService)
: CircuitHandler, IDisposable
{
public override Task OnCircuitOpenedAsync(Circuit circuit,
CancellationToken cancellationToken)
{
authenticationStateProvider.AuthenticationStateChanged +=
AuthenticationChanged;
return base.OnCircuitOpenedAsync(circuit, cancellationToken);
}
private void AuthenticationChanged(Task<AuthenticationState> task)
{
_ = UpdateAuthentication(task);
async Task UpdateAuthentication(Task<AuthenticationState> task)
{
try
{
var state = await task;
userService.SetUser(state.User);
}
catch
{
}
}
}
public override async Task OnConnectionUpAsync(Circuit circuit,
CancellationToken cancellationToken)
{
var state = await authenticationStateProvider.GetAuthenticationStateAsync();
userService.SetUser(state.User);
}
public void Dispose()
{
authenticationStateProvider.AuthenticationStateChanged -=
AuthenticationChanged;
}
}
using System.Security.Claims;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Server.Circuits;
public class UserService
{
private ClaimsPrincipal currentUser = new ClaimsPrincipal(new ClaimsIdentity());
public ClaimsPrincipal GetUser()
{
return currentUser;
}
internal void SetUser(ClaimsPrincipal user)
{
if (currentUser != user)
{
currentUser = user;
}
}
}
internal sealed class UserCircuitHandler : CircuitHandler, IDisposable
{
private readonly AuthenticationStateProvider authenticationStateProvider;
private readonly UserService userService;
public UserCircuitHandler(
AuthenticationStateProvider authenticationStateProvider,
UserService userService)
{
this.authenticationStateProvider = authenticationStateProvider;
this.userService = userService;
}
public override Task OnCircuitOpenedAsync(Circuit circuit,
CancellationToken cancellationToken)
{
authenticationStateProvider.AuthenticationStateChanged +=
AuthenticationChanged;
return base.OnCircuitOpenedAsync(circuit, cancellationToken);
}
private void AuthenticationChanged(Task<AuthenticationState> task)
{
_ = UpdateAuthentication(task);
async Task UpdateAuthentication(Task<AuthenticationState> task)
{
try
{
var state = await task;
userService.SetUser(state.User);
}
catch
{
}
}
}
public override async Task OnConnectionUpAsync(Circuit circuit,
CancellationToken cancellationToken)
{
var state = await authenticationStateProvider.GetAuthenticationStateAsync();
userService.SetUser(state.User);
}
public void Dispose()
{
authenticationStateProvider.AuthenticationStateChanged -=
AuthenticationChanged;
}
}
In der Program-Datei:
using Microsoft.AspNetCore.Components.Server.Circuits;
using Microsoft.Extensions.DependencyInjection.Extensions;
...
builder.Services.AddScoped<UserService>();
builder.Services.TryAddEnumerable(
ServiceDescriptor.Scoped<CircuitHandler, UserCircuitHandler>());
In Startup.ConfigureServices von Startup.cs:
using Microsoft.AspNetCore.Components.Server.Circuits;
using Microsoft.Extensions.DependencyInjection.Extensions;
...
services.AddScoped<UserService>();
services.TryAddEnumerable(
ServiceDescriptor.Scoped<CircuitHandler, UserCircuitHandler>());
Verwenden Sie den Dienst in einer Komponente, um den Benutzer abzurufen:
@inject UserService UserService
<h1>Hello, @(UserService.GetUser().Identity?.Name ?? "world")!</h1>
Um Benutzer*innen in Middleware für MVC, Razor Pages und in anderen ASP.NET Core-Szenarien festzulegen, rufen Sie SetUser für UserService in benutzerdefinierter Middleware auf, wenn die Authentifizierungsmiddleware ausgeführt wird, oder legen Sie Benutzer*innen mit einer IClaimsTransformation-Implementierung fest. Im folgenden Beispiel wird der Middlewareansatz übernommen.
UserServiceMiddleware.cs:
public class UserServiceMiddleware
{
private readonly RequestDelegate next;
public UserServiceMiddleware(RequestDelegate next)
{
this.next = next ?? throw new ArgumentNullException(nameof(next));
}
public async Task InvokeAsync(HttpContext context, UserService service)
{
service.SetUser(context.User);
await next(context);
}
}
Rufen Sie unmittelbar vor dem Aufruf von app.MapRazorComponents<App>() in der Program-Datei die Middleware auf:
Rufen Sie unmittelbar vor dem Aufruf von app.MapBlazorHub() in der Program-Datei die Middleware auf:
Rufen Sie unmittelbar vor dem Aufruf von app.MapBlazorHub() in Startup.Configure von Startup.cs die Middleware auf:
app.UseMiddleware<UserServiceMiddleware>();
Zugreifen auf AuthenticationStateProvider in Middleware für ausgehende Anforderungen
Auf den Authentifizierungszustandsanbieter (AuthenticationStateProvider) eines delegierenden Handlers (DelegatingHandler) für einen HTTP-Client (HttpClient), der mit IHttpClientFactory erstellt wurde, kann in Middleware für ausgehende Anforderungen mithilfe eines Leitungsaktivitätshandlers zugegriffen werden.
Hinweis
Allgemeine Anleitungen zum Definieren von delegierenden Handlern für HTTP-Anforderungen von HttpClient-Instanzen, die mit IHttpClientFactory in ASP.NET Core-Apps erstellt wurden, finden Sie in den folgenden Abschnitten des Artikels zum Stellen von HTTP-Anforderungen mithilfe von IHttpClientFactory in ASP.NET Core:
Im folgenden Beispiel wird AuthenticationStateProvider verwendet, um einen benutzerdefinierten Benutzernamenheader für authentifizierte Benutzer*innen an ausgehende Anforderungen anzufügen.
Implementieren Sie zunächst die CircuitServicesAccessor-Klasse im folgenden Abschnitt des Artikels zur Blazor-Abhängigkeitsinjektion (Dependency Injection, DI):
Zugreifen auf serverseitige Blazor-Dienste aus einem anderen DI-Bereich
Verwenden Sie CircuitServicesAccessor, um auf AuthenticationStateProvider in der DelegatingHandler-Implementierung zuzugreifen.
AuthenticationStateHandler.cs:
using Microsoft.AspNetCore.Components.Authorization;
public class AuthenticationStateHandler(
CircuitServicesAccessor circuitServicesAccessor)
: DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
var authStateProvider = circuitServicesAccessor.Services?
.GetRequiredService<AuthenticationStateProvider>();
if (authStateProvider is null)
{
throw new Exception("AuthenticationStateProvider not available");
}
var authState = await authStateProvider.GetAuthenticationStateAsync();
var user = authState?.User;
if (user?.Identity is not null && user.Identity.IsAuthenticated)
{
request.Headers.Add("X-USER-IDENTITY-NAME", user.Identity.Name);
}
return await base.SendAsync(request, cancellationToken);
}
}
Registrieren Sie Program in der AuthenticationStateHandler-Datei, und fügen Sie den Handler zum IHttpClientFactory-Element hinzu, mit dem HttpClient-Instanzen erstellt werden:
builder.Services.AddTransient<AuthenticationStateHandler>();
builder.Services.AddHttpClient("HttpMessageHandler")
.AddHttpMessageHandler<AuthenticationStateHandler>();
ASP.NET Core