Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Notitie
Dit is niet de nieuwste versie van dit artikel. Zie de .NET 9-versie van dit artikelvoor de huidige release.
Waarschuwing
Deze versie van ASP.NET Core wordt niet meer ondersteund. Zie de .NET- en .NET Core-ondersteuningsbeleidvoor meer informatie. Zie de .NET 9-versie van dit artikelvoor de huidige release.
Belangrijk
Deze informatie heeft betrekking op een pre-releaseproduct dat aanzienlijk kan worden gewijzigd voordat het commercieel wordt uitgebracht. Microsoft geeft geen garanties, uitdrukkelijk of impliciet, met betrekking tot de informatie die hier wordt verstrekt.
Zie de .NET 9-versie van dit artikelvoor de huidige release.
In dit artikel wordt uitgelegd hoe u Blazor aan de serverzijde configureert voor aanvullende beveiligingsscenario's, waaronder het doorgeven van tokens aan een Blazor-app.
Notitie
De codevoorbeelden in dit artikel maken gebruik van nullable reference types (NRT's) en .NET compiler statische null-state analyse, die worden ondersteund in ASP.NET Core vanaf .NET 6 of hoger. Wanneer u .NET 5 of eerder als doel gebruikt, verwijdert u de null-typeaanduiding (?) uit de string?, TodoItem[]?, WeatherForecast[]? en IEnumerable<GitHubBranch>? typen in de voorbeelden van het artikel.
Tokens doorgeven aan een Blazor-app aan de serverzijde
Deze sectie is van toepassing op Blazor Web Apps. Bekijk Blazor Serverde .NET 7-versie van dit artikel voor meer informatie.
Als u alleen toegangstokens wilt gebruiken om web-API-aanroepen uit te voeren vanaf een Blazor Web App met een benoemde HTTP-client, raadpleegt u de sectie Een tokenhandler gebruiken voor web-API-aanroepen , waarin wordt uitgelegd hoe u een DelegatingHandler implementatie gebruikt om het toegangstoken van een gebruiker toe te voegen aan uitgaande aanvragen. De volgende richtlijnen in deze sectie zijn bedoeld voor ontwikkelaars die toegangstokens nodig hebben, tokens vernieuwen en andere verificatie-eigenschappen aan de serverzijde voor andere doeleinden.
Als u tokens en andere verificatie-eigenschappen wilt opslaan voor gebruik aan de serverzijde in Blazor Web Apps, raden we u aan (IHttpContextAccessor/HttpContext,IHttpContextAccessor) te gebruiken HttpContext . Het lezen van tokens van HttpContext, inclusief als een trapsgewijze parameter met behulp van IHttpContextAccessor, wordt ondersteund voor het verkrijgen van tokens voor gebruik tijdens interactieve server-rendering als de tokens worden verkregen tijdens statische server-side rendering (statische SSR) of prerendering. Tokens worden echter niet bijgewerkt als de gebruiker zich verifieert nadat het circuit tot stand is gebracht, omdat de HttpContext tokens worden vastgelegd aan het begin van de SignalR verbinding. Bovendien betekent het gebruik van AsyncLocal<T> door IHttpContextAccessor dat u moet oppassen dat u de uitvoeringscontext niet verliest voordat u de HttpContext leest. Zie IHttpContextAccessor/HttpContext in ASP.NET Core Blazor-appsvoor meer informatie.
In een serviceklasse krijgt u toegang tot de leden van de naamruimte Microsoft.AspNetCore.Authentication om de GetTokenAsync-methode op HttpContext beschikbaar te maken. Een alternatieve benadering, die in het volgende voorbeeld wordt uitgecommentarieerd, is om AuthenticateAsync op HttpContext aan te roepen. Voor de geretourneerde AuthenticateResult.Properties roep GetTokenValue aan.
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;
}
}
De service is geregistreerd in het bestand van Program het serverproject:
builder.Services.AddScoped<AuthenticationProcessor>();
AuthenticationProcessor kan worden geïnjecteerd in server-side services, bijvoorbeeld in een DelegatingHandler voor een vooraf geconfigureerde HttpClient. Het volgende voorbeeld is alleen bedoeld voor demonstratiedoeleinden of als u speciale verwerking in de AuthenticationProcessor service moet uitvoeren, omdat u het token rechtstreeks kunt injecteren IHttpContextAccessor en verkrijgen voor het aanroepen van externe web-API's (zie de sectie IHttpContextAccessor voor meer informatie over het rechtstreeks aanroepen van web-API's).
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);
}
}
De tokenhandler is geregistreerd en fungeert als de delegerende handler voor een benoemde HTTP-client in het Program bestand:
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>();
Waarschuwing
Zorg ervoor dat tokens nooit worden verzonden en verwerkt door de client (het .Client project), bijvoorbeeld in een onderdeel dat interactieve automatische rendering gebruikt en wordt weergegeven op de client of door een service aan de clientzijde. Laat de client de server (project) altijd aanroepen om aanvragen met tokens te verwerken.
Tokens en andere verificatiegegevens mogen de server nooit verlaten.
Zie ASP.NET Core-verificatie Blazor en -autorisatie voor interactieve onderdelen. Hier ziet u hoe u toegangstokens en andere verificatie-eigenschappen op de server kunt achterlaten. Overweeg ook om het BFF-patroon (Backend-for-Frontend) te gebruiken, dat een vergelijkbare oproepstructuur gebruikt en wordt beschreven in Secure an ASP.NET Core Blazor Web App with OpenID Connect (OIDC) voor OIDC-providers en een ASP.NET Core Blazor Web App beveiligen met Microsoft Entra ID voor Microsoft Identity Web met Entra.
Een tokenhandler gebruiken voor web-API-aanroepen
De volgende aanpak is gericht op het koppelen van het toegangstoken van een gebruiker aan uitgaande aanvragen, met name om web-API-aanroepen te maken naar externe web-API-apps. De benadering wordt weergegeven voor een Blazor Web App die gebruikmaakt van wereldwijde Interactive Server-rendering, maar dezelfde algemene benadering is van toepassing op Blazor Web Apps die gebruikmaken van de globale interactieve automatische rendermodus. Het belangrijke om te onthouden is dat via HttpContext toegang krijgen tot het IHttpContextAccessor alleen op de server gebeurt.
Voor een demonstratie van de richtlijnen in deze sectie, zie de voorbeeld-apps BlazorWebAppOidc en BlazorWebAppOidcServer (.NET 8 of hoger) in de Blazor GitHub-repository met voorbeelden. De voorbeelden gebruiken een globale interactieve rendermodus en OIDC-verificatie met Microsoft Entra zonder entra-specifieke pakketten te gebruiken. De voorbeelden laten zien hoe u een JWT-toegangstoken doorgeeft om een beveiligde web-API aan te roepen.
Microsoft Identity Platform met Microsoft Identity Web Packages voor Microsoft Entra ID biedt een API voor het aanroepen van web-API's van Blazor Web Apps met automatisch tokenbeheer en verlenging. Zie Een ASP.NET Core Blazor Web App beveiligen met Microsoft Entra-id en de BlazorWebAppEntra voorbeeld-apps BlazorWebAppEntraBff (.NET 9 of hoger) in de Blazor GitHub-opslagplaats met voorbeelden voor meer informatie.
Subklasse DelegatingHandler om het toegangstoken van een gebruiker toe te voegen aan uitgaande aanvragen. De tokenhandler wordt alleen uitgevoerd op de server, dus het gebruik HttpContext is veilig.
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);
}
}
Notitie
Zie de sectie AuthenticationStateProvider voor begeleiding over hoe een DelegatingHandler toegankelijk is vanuit een AuthenticationStateProvider.
In het Program-bestand van het project wordt de tokenhandler (TokenHandler) geregistreerd als een 'scoped service' en opgegeven als een berichtafhandelaar met behulp van de gespecificeerde naam van de HTTP-client en .
In het volgende voorbeeld is de {HTTP CLIENT NAME} tijdelijke aanduiding de naam van de HttpClient, en is de {BASE ADDRESS} tijdelijke aanduiding het basisadres-URI van de web-API. Zie voor meer informatie over AddHttpContextAccessorIHttpContextAccessor/HttpContext in ASP.NET Core Blazor-apps.
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>();
Voorbeeld:
builder.Services.AddScoped<TokenHandler>();
builder.Services.AddHttpClient("ExternalApi",
client => client.BaseAddress = new Uri("https://localhost:7277"))
.AddHttpMessageHandler<TokenHandler>();
U kunt het HTTP-clientbasisadres van de configuratie opgeven met builder.Configuration["{CONFIGURATION KEY}"], waarbij de {CONFIGURATION KEY} tijdelijke aanduiding de configuratiesleutel is:
new Uri(builder.Configuration["ExternalApiUri"] ?? throw new IOException("No URI!"))
Specificeer appsettings.json en ExternalApiUri. In het volgende voorbeeld wordt de waarde ingesteld op het localhost-adres van de externe web-API op https://localhost:7277:
"ExternalApiUri": "https://localhost:7277"
Op dit moment kan een HttpClient door een onderdeel gemaakte beveiligde web-API-aanvragen maken. In het volgende voorbeeld is de {REQUEST URI} de relatieve aanvraag-URI en is de {HTTP CLIENT NAME} plaatsaanduiding de naam van de HttpClient:
using var request = new HttpRequestMessage(HttpMethod.Get, "{REQUEST URI}");
var client = ClientFactory.CreateClient("{HTTP CLIENT NAME}");
using var response = await client.SendAsync(request);
Voorbeeld:
using var request = new HttpRequestMessage(HttpMethod.Get, "/weather-forecast");
var client = ClientFactory.CreateClient("ExternalApi");
using var response = await client.SendAsync(request);
Aanvullende functies zijn gepland, dotnet/aspnetcore #52390) is een gesloten probleem dat nuttige discussie en mogelijke tijdelijke oplossingenstrategieën voor geavanceerde gebruiksscenario's bevat.
Tokens die buiten de Razor onderdelen in een Blazor-app aan de serverzijde beschikbaar zijn, kunnen worden doorgegeven aan onderdelen met de methode die in deze sectie wordt beschreven. Het voorbeeld in deze sectie is gericht op het doorgeven van toegangs-, vernieuwings- en XSRF-token (ANTI-request forgery) tokens aan de Blazor-app, maar de methode is geldig voor andere HTTP-contextstatussen.
Notitie
Het doorgeven van het XSRF-token aan Razor onderdelen is handig in scenario's waarin onderdelen POST naar Identity of andere eindpunten die validatie vereisen. Als voor uw app alleen toegangs- en vernieuwingstokens zijn vereist, kunt u de XSRF-tokencode uit het volgende voorbeeld verwijderen.
Verifieer de app zoals u dat zou doen met een gewone Razor Pages- of MVC-app. Verstrek de tokens en sla deze op in de authenticatie cookie.
In het bestand Program:
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);
});
Optioneel kunnen extra bereiken worden toegevoegd met options.Scope.Add("{SCOPE}");, waarbij de tijdelijke aanduiding {SCOPE} het extra bereik is dat moet worden toegevoegd.
Definieer een scoped token-provider-service die kan worden gebruikt binnen de Blazor-app om de tokens te verkrijgen van afhankelijkheidsinjectie (DI).
TokenProvider.cs:
public class TokenProvider
{
public string? AccessToken { get; set; }
public string? RefreshToken { get; set; }
public string? XsrfToken { get; set; }
}
Voeg in het bestand Program services toe voor:
-
IHttpClientFactory: wordt gebruikt in een
WeatherForecastService-klasse die weergegevens ophaalt uit een server-API met een toegangstoken. -
TokenProvider: bevat de toegangs- en vernieuwingstokens.
builder.Services.AddHttpClient();
builder.Services.AddScoped<TokenProvider>();
Voeg in Startup.ConfigureServices van Startup.csdiensten toe voor:
-
IHttpClientFactory: wordt gebruikt in een
WeatherForecastService-klasse die weergegevens ophaalt uit een server-API met een toegangstoken. -
TokenProvider: bevat de toegangs- en vernieuwingstokens.
services.AddHttpClient();
services.AddScoped<TokenProvider>();
Definieer een klasse om de initiële app-status door te geven met de toegangs- en vernieuwingstokens.
InitialApplicationState.cs:
public class InitialApplicationState
{
public string? AccessToken { get; set; }
public string? RefreshToken { get; set; }
public string? XsrfToken { get; set; }
}
Maak en exemplaar van Pages/_Host.cshtml in het InitialApplicationState-bestand en geef het als parameter door aan de app:
Maak en exemplaar van Pages/_Layout.cshtml in het InitialApplicationState-bestand en geef het als parameter door aan de app:
Maak en exemplaar van Pages/_Host.cshtml in het InitialApplicationState-bestand en geef het als parameter door aan de 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" ... />
Los in het App-onderdeel (App.razor) de service op en initialiseer deze met de gegevens uit de 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();
}
}
Notitie
Een alternatief voor het toewijzen van de initiële status aan de TokenProvider in het vorige voorbeeld is het kopiëren van de gegevens naar een gescopeerde service binnen OnInitializedAsync voor gebruik in de hele app.
Voeg een pakketreferentie toe aan de app voor het Microsoft.AspNet.WebApi.Client NuGet-pakket.
Notitie
Zie de artikelen onder Pakketten installeren en beheren binnen de Package consumption workflow (NuGet-documentatie) voor richtlijnen over het toevoegen van pakketten aan .NET-apps. Bevestig de juiste pakketversies op NuGet.org.
In de service die een beveiligde API-aanvraag maakt, injecteert u de tokenprovider en haalt u het token voor de API-aanvraag op:
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>();
}
}
Voor een XSRF-token dat is doorgegeven aan een onderdeel, injecteert u de TokenProvider en voegt u het XSRF-token toe aan de POST-aanvraag. In het volgende voorbeeld wordt het token toegevoegd aan een afmeldingseindpunt POST. Het scenario voor het volgende voorbeeld is dat het afmeldingseindpunt (Areas/Identity/Pages/Account/Logout.cshtml, in de app) geen IgnoreAntiforgeryTokenAttribute (@attribute [IgnoreAntiforgeryToken]) opgeeft omdat er een actie wordt uitgevoerd naast een normale afmeldingsbewerking die moet worden beveiligd. Voor het eindpunt is een geldig XSRF-token vereist om de aanvraag te verwerken.
In een component dat een Logout-knop presenteert aan geautoriseerde gebruikers:
@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>
Het verificatieschema instellen
Voor een app die meer dan één verificatie-middleware gebruikt en dus meer dan één verificatieschema heeft, kan het schema dat Blazor gebruikt expliciet worden ingesteld in de eindpuntconfiguratie van het Program-bestand. In het volgende voorbeeld wordt het OIDC-schema (OpenID Connect) ingesteld:
Voor een app die gebruikmaakt van meer dan één verificatie-middleware en dus meer dan één verificatieschema heeft, kan het schema dat Blazor gebruikt expliciet worden ingesteld in de eindpuntconfiguratie van Startup.cs. In het volgende voorbeeld wordt het OIDC-schema (OpenID Connect) ingesteld:
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
});
Voor een app die gebruikmaakt van meer dan één verificatie-middleware en dus meer dan één verificatieschema heeft, kan het schema dat Blazor gebruikt expliciet worden ingesteld in de eindpuntconfiguratie van Startup.Configure. In het volgende voorbeeld wordt het Microsoft Entra ID-schema ingesteld:
endpoints.MapBlazorHub().RequireAuthorization(
new AuthorizeAttribute
{
AuthenticationSchemes = AzureADDefaults.AuthenticationScheme
});
OpenID Connect -eindpunten (OIDC) v2.0 gebruiken
In versies van ASP.NET Core vóór .NET 5 gebruiken de verificatiebibliotheek en Blazor -sjablonen OpenID Connect (OIDC) v1.0-eindpunten. Als u een v2.0-eindpunt wilt gebruiken met versies van ASP.NET Core vóór .NET 5, configureert u de OpenIdConnectOptions.Authority optie in het OpenIdConnectOptionsvolgende:
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme,
options =>
{
options.Authority += "/v2.0";
}
U kunt de instelling ook maken in het app-instellingenbestand (appsettings.json):
{
"AzureAd": {
"Authority": "https://login.microsoftonline.com/common/oauth2/v2.0/",
...
}
}
Als het toevoegen van een segment aan de instantie niet geschikt is voor de OIDC-provider van de app, zoals bij niet-ME-ID-providers, stelt u de eigenschap Authority rechtstreeks in. Stel de eigenschap in OpenIdConnectOptions of in het app-instellingenbestand in met de Authority sleutel.
Codewijzigingen
De lijst met claims in het id-token wordt gewijzigd voor v2.0-eindpunten. Microsoft-documentatie over de wijzigingen is niet langer beschikbaar, maar richtlijnen voor de claims in een ID-token zijn beschikbaar in de ID-tokenclaimsreferentie.
Aangezien resources zijn opgegeven in scope-URI's voor v2.0-eindpunten, verwijdert u de instelling van de eigenschap OpenIdConnectOptions.Resource in OpenIdConnectOptions:
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options => { ... options.Resource = "..."; // REMOVE THIS LINE ... }
App-ID-URI
- Wanneer u v2.0-eindpunten gebruikt, definiëren API's een
App ID URI, die bedoeld is om een unieke id voor de API weer te geven. - Alle scopes omvatten de app-id-URI als voorvoegsel en de v2.0-eindpunten geven toegangstokens af met de app-id-URI als audience.
- Wanneer u V2.0-eindpunten gebruikt, wordt de client-id die is geconfigureerd in de Server-API gewijzigd van de API-toepassings-id (client-id) in de app-id-URI.
appsettings.json:
{
"AzureAd": {
...
"ClientId": "https://{TENANT}.onmicrosoft.com/{PROJECT NAME}"
...
}
}
U vindt de app-id-URI die u kunt gebruiken in de beschrijving van de registratie van de OIDC-provider-app.
Circuitbeheerder voor het vastleggen van gebruikers voor op maat gemaakte diensten
Gebruik een CircuitHandler om een gebruiker op te slaan uit de AuthenticationStateProvider en de gebruiker in een dienst onderbrengen. Als u de gebruiker wilt bijwerken, registreer dan een callback naar AuthenticationStateChanged en plaats een Task in de wachtrij om de nieuwe gebruiker te verkrijgen en de service bij te werken. In het volgende voorbeeld ziet u de benadering.
In het volgende voorbeeld:
-
OnConnectionUpAsync wordt aangeroepen telkens wanneer het circuit opnieuw verbinding maakt, waarbij de gebruiker de levensduur van de verbinding instelt. Alleen de OnConnectionUpAsync methode is vereist, tenzij u updates implementeert via een handler voor verificatiewijzigingen (
AuthenticationChangedin het volgende voorbeeld). -
OnCircuitOpenedAsync wordt aangeroepen om de gewijzigde handler voor verificatie,
AuthenticationChanged, te koppelen om de gebruiker bij te werken. - Het
catchblok van deUpdateAuthentication-taak neemt geen actie op uitzonderingen omdat er op dit moment geen manier is om de uitzonderingen te rapporteren bij het uitvoeren van code. Als er een foutmelding wordt gegenereerd vanuit de taak, wordt de foutmelding op een andere plek in de app gerapporteerd.
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 het bestand Program:
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 van Startup.cs:
using Microsoft.AspNetCore.Components.Server.Circuits;
using Microsoft.Extensions.DependencyInjection.Extensions;
...
services.AddScoped<UserService>();
services.TryAddEnumerable(
ServiceDescriptor.Scoped<CircuitHandler, UserCircuitHandler>());
Gebruik de service in een component om de gebruiker op te halen.
@inject UserService UserService
<h1>Hello, @(UserService.GetUser().Identity?.Name ?? "world")!</h1>
Als u de gebruiker wilt instellen in middleware voor MVC, Razor Pages en in andere ASP.NET Core-scenario's, roept u SetUser aan op de UserService in aangepaste middleware nadat de verificatie-middleware is uitgevoerd of stelt u de gebruiker in met een IClaimsTransformation-implementatie. In het volgende voorbeeld wordt de middleware-benadering gebruikt.
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);
}
}
Onmiddellijk voordat de aanroep naar app.MapRazorComponents<App>() in het bestand Program, roept u de middleware aan:
Onmiddellijk voordat de aanroep naar app.MapBlazorHub() in het bestand Program, roept u de middleware aan:
Roep de middleware aan vlak voordat je de oproep naar app.MapBlazorHub() in Startup.Configure van Startup.csdoet:
app.UseMiddleware<UserServiceMiddleware>();
Toegang tot AuthenticationStateProvider in middleware voor uitgaande verzoeken
De AuthenticationStateProvider van een DelegatingHandler voor HttpClient die met IHttpClientFactory is gemaakt, kan worden benaderd in middleware voor uitgaande verzoeken via een circuitactiviteitshandler.
Notitie
Zie de volgende secties van HttpClientvoor algemene richtlijnen voor het definiëren van de delegeringshandlers voor HTTP-aanvragen door IHttpClientFactory instanties die zijn gemaakt met behulp van in ASP.NET Core-apps:
In het volgende voorbeeld wordt AuthenticationStateProvider gebruikt om een aangepaste gebruikersnaamheader toe te voegen voor geverifieerde gebruikers aan uitgaande aanvragen.
Implementeer eerst de CircuitServicesAccessor-klasse in de volgende sectie van het artikel Blazor afhankelijkheidsinjectie (DI):
Toegang tot server-side Blazor services vanuit een andere DI-scope
Gebruik de CircuitServicesAccessor voor toegang tot de AuthenticationStateProvider in de DelegatingHandler-implementatie.
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);
}
}
Registreer in het Program bestand de AuthenticationStateHandler en voeg de handler toe aan de IHttpClientFactory waarmee HttpClient exemplaren worden gemaakt:
builder.Services.AddTransient<AuthenticationStateHandler>();
builder.Services.AddHttpClient("HttpMessageHandler")
.AddHttpMessageHandler<AuthenticationStateHandler>();