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.
Note
Dit is niet de nieuwste versie van dit artikel. Zie de .NET 9-versie van dit artikelvoor de huidige release.
Warning
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.
Important
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 worden aanvullende beveiligingsscenario's voor Blazor WebAssembly apps beschreven.
Tokens koppelen aan uitgaande aanvragen
AuthorizationMessageHandler DelegatingHandler wordt gebruikt om toegangstokens te verwerken. Tokens worden verkregen met behulp van de IAccessTokenProvider service, die is geregistreerd door het framework. Als een token niet kan worden verkregen, wordt er een AccessTokenNotAvailableException gegenereerd. AccessTokenNotAvailableException heeft een Redirect-methode die naar AccessTokenResult.InteractiveRequestUrl navigeert met behulp van de opgegeven AccessTokenResult.InteractionOptions om het toegangstoken te vernieuwen.
Voor het gemak biedt het framework het BaseAddressAuthorizationMessageHandler vooraf geconfigureerde basisadres van de app als een geautoriseerde URL. Toegangstokens worden alleen toegevoegd wanneer de aanvraag-URI zich binnen de basis-URI van de app bevindt. Wanneer uitgaande aanvraag-URI's zich niet binnen de basis-URI van de app bevinden, kunt u een aangepaste AuthorizationMessageHandler klasse (aanbevolen) gebruiken of de AuthorizationMessageHandler configureren.
Note
Naast de configuratie van de client-app voor server-API-toegang moet de server-API ook CORS (Cross-Origin Requests) toestaan wanneer de client en de server zich niet op hetzelfde basisadres bevinden. Zie de sectie Cross-Origin Resource Sharing (CORS) verderop in dit artikel voor meer informatie over CORS-configuratie aan de serverzijde.
In het volgende voorbeeld:
-
AddHttpClient voegt IHttpClientFactory en gerelateerde services toe aan de serviceverzameling en configureert een benoemde HttpClient (
WebAPI). HttpClient.BaseAddress is het basisadres van de resource-URI bij het verzenden van aanvragen. IHttpClientFactory wordt geleverd door hetMicrosoft.Extensions.HttpNuGet-pakket. - BaseAddressAuthorizationMessageHandler wordt gebruikt voor het DelegatingHandler verwerken van toegangstokens. Toegangstokens worden alleen toegevoegd wanneer de aanvraag-URI zich binnen de basis-URI van de app bevindt.
-
IHttpClientFactory.CreateClient maakt en configureert een HttpClient exemplaar voor uitgaande aanvragen met behulp van de configuratie die overeenkomt met de benoemde HttpClient (
WebAPI).
In het volgende voorbeeld HttpClientFactoryServiceCollectionExtensions.AddHttpClient is een extensie in Microsoft.Extensions.Http. Voeg het pakket toe aan een app die er nog niet naar verwijst.
Note
Zie de artikelen onder Pakketten installeren en beheren bij Verbruikswerkstroom voor pakketten (NuGet-documentatie)voor begeleiding bij het toevoegen van pakketten in .NET-apps. Bevestig de juiste pakketversies op NuGet.org.
using System.Net.Http;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
...
builder.Services.AddHttpClient("WebAPI",
client => client.BaseAddress = new Uri("https://api.contoso.com/v1.0"))
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>()
.CreateClient("WebAPI"));
Voor een gehoste Blazoroplossing op basis van de Blazor WebAssembly projectsjabloon bevinden aanvraag-URI's zich binnen de basis-URI van de app.
IWebAssemblyHostEnvironment.BaseAddress Daarom wordt (new Uri(builder.HostEnvironment.BaseAddress)) toegewezen aan de HttpClient.BaseAddress app die is gegenereerd op basis van de projectsjabloon.
De geconfigureerde HttpClient wordt gebruikt om geautoriseerde verzoeken te doen met behulp van het try-catch patroon.
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject HttpClient Http
...
protected override async Task OnInitializedAsync()
{
try
{
var examples =
await Http.GetFromJsonAsync<ExampleType[]>("ExampleAPIMethod");
...
}
catch (AccessTokenNotAvailableException exception)
{
exception.Redirect();
}
}
Scenario's voor aangepaste verificatieaanvragen
In de volgende scenario's ziet u hoe u verificatieaanvragen aanpast en hoe u het aanmeldingspad kunt verkrijgen via verificatieopties.
Het aanmeldingsproces aanpassen
Beheer aanvullende parameters voor een aanmeldingsaanvraag met de volgende methoden een of meer keren op een nieuw exemplaar van InteractiveRequestOptions:
In het volgende LoginDisplay onderdeelvoorbeeld worden extra parameters toegevoegd aan de aanmeldingsaanvraag:
-
promptis ingesteld oplogin: Dwingt de gebruiker om hun referenties op die aanvraag in te voeren, waarbij eenmalige aanmelding wordt genegeerd. -
loginHintis ingesteld oppeter@contoso.com: prefillt het veld voor gebruikersnaam/e-mailadres op de aanmeldingspagina voor de gebruiker naarpeter@contoso.com. Apps gebruiken deze parameter vaak tijdens opnieuw verificatie, nadat de gebruikersnaam al is geëxtraheerd uit een vorige aanmelding met behulp van depreferred_usernameclaim.
Shared/LoginDisplay.razor:
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject NavigationManager Navigation
<AuthorizeView>
<Authorized>
Hello, @context.User.Identity?.Name!
<button @onclick="BeginLogOut">Log out</button>
</Authorized>
<NotAuthorized>
<button @onclick="BeginLogIn">Log in</button>
</NotAuthorized>
</AuthorizeView>
@code{
public void BeginLogOut()
{
Navigation.NavigateToLogout("authentication/logout");
}
public void BeginLogIn()
{
InteractiveRequestOptions requestOptions =
new()
{
Interaction = InteractionType.SignIn,
ReturnUrl = Navigation.Uri,
};
requestOptions.TryAddAdditionalParameter("prompt", "login");
requestOptions.TryAddAdditionalParameter("loginHint", "peter@contoso.com");
Navigation.NavigateToLogin("authentication/login", requestOptions);
}
}
Zie de volgende bronnen voor meer informatie:
Opties aanpassen voordat u een token interactief verkrijgt
Als er zich een AccessTokenNotAvailableException voordoet, kunt u aanvullende parameters beheren voor een nieuwe toegangstoken-aanvraag van een identiteitsprovider met behulp van de volgende methoden, één of meerdere keren op een nieuw exemplaar van InteractiveRequestOptions.
In het volgende voorbeeld waarmee JSON-gegevens worden opgehaald via web-API, worden extra parameters toegevoegd aan de omleidingsaanvraag als er geen toegangstoken beschikbaar is (AccessTokenNotAvailableException wordt gegenereerd):
-
promptis ingesteld oplogin: Dwingt de gebruiker om hun referenties op die aanvraag in te voeren, waarbij eenmalige aanmelding wordt genegeerd. -
loginHintis ingesteld oppeter@contoso.com: prefillt het veld voor gebruikersnaam/e-mailadres op de aanmeldingspagina voor de gebruiker naarpeter@contoso.com. Apps gebruiken deze parameter vaak tijdens opnieuw verificatie, nadat de gebruikersnaam al is geëxtraheerd uit een vorige aanmelding met behulp van depreferred_usernameclaim.
try
{
var examples = await Http.GetFromJsonAsync<ExampleType[]>("ExampleAPIMethod");
...
}
catch (AccessTokenNotAvailableException ex)
{
ex.Redirect(requestOptions => {
requestOptions.TryAddAdditionalParameter("prompt", "login");
requestOptions.TryAddAdditionalParameter("loginHint", "peter@contoso.com");
});
}
In het voorgaande voorbeeld wordt ervan uitgegaan dat:
- De aanwezigheid van een
@using/usinginstructie voor API in de Microsoft.AspNetCore.Components.WebAssembly.Authentication naamruimte. -
HttpClientgeïnjecteerd alsHttp.
Zie de volgende bronnen voor meer informatie:
Opties aanpassen bij het gebruik van een IAccessTokenProvider
Als het verkrijgen van een token mislukt wanneer u een IAccessTokenProvidertoken gebruikt, beheert u aanvullende parameters voor een nieuwe toegangstokenaanvraag van een id-provider met de volgende methoden een of meer keren op een nieuw exemplaar van InteractiveRequestOptions:
In het volgende voorbeeld dat probeert een toegangstoken voor de gebruiker te verkrijgen, worden aanvullende parameters toegevoegd aan de aanmeldingsaanvraag als de poging om een token te verkrijgen mislukt wanneer TryGetToken wordt aangeroepen:
-
promptis ingesteld oplogin: Dwingt de gebruiker om hun referenties op die aanvraag in te voeren, waarbij eenmalige aanmelding wordt genegeerd. -
loginHintis ingesteld oppeter@contoso.com: prefillt het veld voor gebruikersnaam/e-mailadres op de aanmeldingspagina voor de gebruiker naarpeter@contoso.com. Apps gebruiken deze parameter vaak tijdens opnieuw verificatie, nadat de gebruikersnaam al is geëxtraheerd uit een vorige aanmelding met behulp van depreferred_usernameclaim.
var tokenResult = await TokenProvider.RequestAccessToken(
new AccessTokenRequestOptions
{
Scopes = [ ... ]
});
if (!tokenResult.TryGetToken(out var token))
{
tokenResult.InteractionOptions.TryAddAdditionalParameter("prompt", "login");
tokenResult.InteractionOptions.TryAddAdditionalParameter("loginHint",
"peter@contoso.com");
Navigation.NavigateToLogin(accessTokenResult.InteractiveRequestUrl,
accessTokenResult.InteractionOptions);
}
var tokenResult = await TokenProvider.RequestAccessToken(
new AccessTokenRequestOptions
{
Scopes = new[] { ... }
});
if (!tokenResult.TryGetToken(out var token))
{
tokenResult.InteractionOptions.TryAddAdditionalParameter("prompt", "login");
tokenResult.InteractionOptions.TryAddAdditionalParameter("loginHint",
"peter@contoso.com");
Navigation.NavigateToLogin(accessTokenResult.InteractiveRequestUrl,
accessTokenResult.InteractionOptions);
}
In het voorgaande voorbeeld wordt ervan uitgegaan:
- De aanwezigheid van een
@using/usinginstructie voor API in de Microsoft.AspNetCore.Components.WebAssembly.Authentication naamruimte. -
IAccessTokenProvider geïnjecteerd als
TokenProvider.
Zie de volgende bronnen voor meer informatie:
Afmelden met een aangepaste retour-URL
In het volgende voorbeeld wordt de gebruiker afgelogd en wordt de gebruiker geretourneerd naar het /goodbye eindpunt:
Navigation.NavigateToLogout("authentication/logout", "goodbye");
Verkrijg het aanmeldingspad uit de authenticatieopties
Haal het geconfigureerde aanmeldingspad op van RemoteAuthenticationOptions:
var loginPath =
RemoteAuthOptions.Get(Options.DefaultName).AuthenticationPaths.LogInPath;
In het voorgaande voorbeeld wordt ervan uitgegaan:
- De aanwezigheid van een
@using/usingstatement voor API in de volgende naamruimten: -
IOptionsSnapshot<RemoteAuthenticationOptions<ApiAuthorizationProviderOptions>>geïnjecteerd alsRemoteAuthOptions.
Aangepaste AuthorizationMessageHandler klasse
Deze richtlijnen in deze sectie worden aanbevolen voor client-apps die uitgaande aanvragen verzenden naar URI's die zich niet binnen de basis-URI van de app bevindt.
In het volgende voorbeeld breidt een aangepaste klasse AuthorizationMessageHandler uit voor gebruik als de DelegatingHandler voor een HttpClient. ConfigureHandler configureert deze handler om uitgaande HTTP-aanvragen te autoriseren met behulp van een toegangstoken. Het toegangstoken wordt alleen gekoppeld als ten minste één van de geautoriseerde URL's een basis is van de aanvraag-URI (HttpRequestMessage.RequestUri).
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
public class CustomAuthorizationMessageHandler : AuthorizationMessageHandler
{
public CustomAuthorizationMessageHandler(IAccessTokenProvider provider,
NavigationManager navigation)
: base(provider, navigation)
{
ConfigureHandler(
authorizedUrls: [ "https://api.contoso.com/v1.0" ],
scopes: [ "example.read", "example.write" ]);
}
}
Note
In deze sectie wordt de voorgaande berichthandler gebruikt wanneer een geconfigureerde HttpClient wordt gemaakt op basis van een geïnjecteerd IHttpClientFactory. Als u geen IHttpClientFactory gebruikt, moet u een HttpClientHandler-exemplaar maken en het toewijzen aan de AuthorizationMessageHandler van de DelegatingHandler.InnerHandler.
InnerHandler = new HttpClientHandler();
U hoeft de voorgaande InnerHandler opdracht niet uit te voeren als u deze gebruikt IHttpClientFactory, zoals de ExampleAPIMethod aanroep verderop in deze sectie laat zien.
In de voorgaande code zijn de bereiken example.read en example.write algemene voorbeelden die niet bedoeld zijn om geldige bereiken voor een bepaalde provider weer te geven.
In het Program bestand wordt CustomAuthorizationMessageHandler geregistreerd als een kortstondige service en geconfigureerd als de DelegatingHandler voor uitgaande HttpResponseMessage instanties die zijn gemaakt door een met name genoemde HttpClient.
In het volgende voorbeeld HttpClientFactoryServiceCollectionExtensions.AddHttpClient is een extensie in Microsoft.Extensions.Http. Voeg het pakket toe aan een app die er nog niet naar verwijst.
Note
Zie de artikelen onder Pakketten installeren en beheren bij Verbruikswerkstroom voor pakketten (NuGet-documentatie)voor begeleiding bij het toevoegen van pakketten in .NET-apps. Bevestig de juiste pakketversies op NuGet.org.
builder.Services.AddTransient<CustomAuthorizationMessageHandler>();
builder.Services.AddHttpClient("WebAPI",
client => client.BaseAddress = new Uri("https://api.contoso.com/v1.0"))
.AddHttpMessageHandler<CustomAuthorizationMessageHandler>();
Note
In het voorgaande voorbeeld wordt de CustomAuthorizationMessageHandlerDelegatingHandler service geregistreerd als een tijdelijke service voor AddHttpMessageHandler. Tijdelijke registratie wordt aanbevolen voor IHttpClientFactory, waarmee zijn eigen DI-bereiken worden beheerd. Zie de volgende bronnen voor meer informatie:
Voor een gehoste Blazor oplossing op basis van de Blazor WebAssembly projectsjabloon wordt IWebAssemblyHostEnvironment.BaseAddress (new Uri(builder.HostEnvironment.BaseAddress)) toegewezen aan de HttpClient.BaseAddress.
De geconfigureerde HttpClient wordt gebruikt om geautoriseerde verzoeken te doen met behulp van het try-catch patroon. Wanneer de client wordt gemaakt met CreateClient (Microsoft.Extensions.Http pakket), worden de HttpClient voorzien van instanties die toegangstokens bevatten bij aanvragen aan de server-API. Als de aanvraag-URI een relatieve URI is, zoals in het volgende voorbeeld (ExampleAPIMethod), wordt deze gecombineerd met het BaseAddress moment waarop de client-app de aanvraag doet:
@inject IHttpClientFactory ClientFactory
...
@code {
protected override async Task OnInitializedAsync()
{
try
{
var client = ClientFactory.CreateClient("WebAPI");
var examples =
await client.GetFromJsonAsync<ExampleType[]>("ExampleAPIMethod");
...
}
catch (AccessTokenNotAvailableException exception)
{
exception.Redirect();
}
}
}
AuthorizationMessageHandler configureren
AuthorizationMessageHandler kan worden geconfigureerd met geautoriseerde URL's, scopes en een retour-URL via de ConfigureHandler methode. ConfigureHandler hiermee configureert u de handler voor het autoriseren van uitgaande HTTP-aanvragen met behulp van een toegangstoken. Het toegangstoken wordt alleen gekoppeld als ten minste één van de geautoriseerde URL's een basis is van de aanvraag-URI (HttpRequestMessage.RequestUri). Als de aanvraag-URI een relatieve URI is, wordt deze gecombineerd met de BaseAddress.
In het volgende voorbeeld AuthorizationMessageHandler configureert u een HttpClient in het Program bestand:
using System.Net.Http;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
...
builder.Services.AddScoped(sp => new HttpClient(
sp.GetRequiredService<AuthorizationMessageHandler>()
.ConfigureHandler(
authorizedUrls: [ "https://api.contoso.com/v1.0" ],
scopes: [ "example.read", "example.write" ])
.InnerHandler = new HttpClientHandler())
{
BaseAddress = new Uri("https://api.contoso.com/v1.0")
});
In de voorgaande code:
- De scopes
example.readenexample.writezijn generieke voorbeelden die niet bedoeld zijn om geldige scopes voor een bepaalde provider weer te geven. - IHttpClientFactory wordt niet gebruikt om HttpClient-exemplaren te maken, dus wordt er handmatig een HttpClientHandler-exemplaar gemaakt en toegewezen aan de AuthorizationMessageHandler's DelegatingHandler.InnerHandler.
Voor een gehoste Blazor oplossing op basis van de Blazor WebAssembly projectsjabloon wordt IWebAssemblyHostEnvironment.BaseAddress het volgende toegewezen:
- De HttpClient.BaseAddress (
new Uri(builder.HostEnvironment.BaseAddress)). - Een URL van de
authorizedUrlsmatrix.
Getypt HttpClient
Er kan een getypte client worden gedefinieerd die alle HTTP- en tokenacquisitiezaken in een enkele klasse afhandelt.
WeatherForecastClient.cs:
using System.Net.Http.Json;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using static {PACKAGE ID/ASSEMBLY NAME}.Data;
public class WeatherForecastClient(HttpClient http)
{
private WeatherForecast[]? forecasts;
public async Task<WeatherForecast[]> GetForecastAsync()
{
try
{
forecasts = await http.GetFromJsonAsync<WeatherForecast[]>(
"WeatherForecast");
}
catch (AccessTokenNotAvailableException exception)
{
exception.Redirect();
}
return forecasts ?? Array.Empty<WeatherForecast>();
}
}
In het voorgaande voorbeeld is het WeatherForecast type een statische klasse die weersvoorspellingsgegevens bevat. De {PACKAGE ID/ASSEMBLY NAME} tijdelijke aanduiding is de pakket-id van het project (<PackageId> in het projectbestand) voor een bibliotheek- of assemblynaam voor een app (bijvoorbeeld using static BlazorSample.Data;).
In het volgende voorbeeld HttpClientFactoryServiceCollectionExtensions.AddHttpClient is een extensie in Microsoft.Extensions.Http. Voeg het pakket toe aan een app die er nog niet naar verwijst.
Note
Zie de artikelen onder Pakketten installeren en beheren bij Verbruikswerkstroom voor pakketten (NuGet-documentatie)voor begeleiding bij het toevoegen van pakketten in .NET-apps. Bevestig de juiste pakketversies op NuGet.org.
In het bestand Program:
using System.Net.Http;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
...
builder.Services.AddHttpClient<WeatherForecastClient>(
client => client.BaseAddress = new Uri("https://api.contoso.com/v1.0"))
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
Voor een gehoste Blazor oplossing op basis van de Blazor WebAssembly projectsjabloon wordt IWebAssemblyHostEnvironment.BaseAddress (new Uri(builder.HostEnvironment.BaseAddress)) toegewezen aan de HttpClient.BaseAddress.
In een onderdeel waarmee weergegevens worden opgehaald:
@inject WeatherForecastClient Client
...
protected override async Task OnInitializedAsync()
{
forecasts = await Client.GetForecastAsync();
}
De HttpClient handler configureren
De handler kan worden geconfigureerd met ConfigureHandler voor uitgaande HTTP-aanvragen.
In het volgende voorbeeld HttpClientFactoryServiceCollectionExtensions.AddHttpClient is een extensie in Microsoft.Extensions.Http. Voeg het pakket toe aan een app die er nog niet naar verwijst.
Note
Zie de artikelen onder Pakketten installeren en beheren bij Verbruikswerkstroom voor pakketten (NuGet-documentatie)voor begeleiding bij het toevoegen van pakketten in .NET-apps. Bevestig de juiste pakketversies op NuGet.org.
In het bestand Program:
builder.Services.AddHttpClient<WeatherForecastClient>(
client => client.BaseAddress = new Uri("https://api.contoso.com/v1.0"))
.AddHttpMessageHandler(sp => sp.GetRequiredService<AuthorizationMessageHandler>()
.ConfigureHandler(
authorizedUrls: [ "https://api.contoso.com/v1.0" ],
scopes: [ "example.read", "example.write" ]));
builder.Services.AddHttpClient<WeatherForecastClient>(
client => client.BaseAddress = new Uri("https://api.contoso.com/v1.0"))
.AddHttpMessageHandler(sp => sp.GetRequiredService<AuthorizationMessageHandler>()
.ConfigureHandler(
authorizedUrls: new[] { "https://api.contoso.com/v1.0" },
scopes: new[] { "example.read", "example.write" }));
In de voorgaande code zijn de bereiken example.read en example.write algemene voorbeelden die niet bedoeld zijn om geldige bereiken voor een bepaalde provider weer te geven.
Voor een gehoste Blazor oplossing op basis van de Blazor WebAssembly projectsjabloon wordt IWebAssemblyHostEnvironment.BaseAddress het volgende toegewezen:
- De HttpClient.BaseAddress (
new Uri(builder.HostEnvironment.BaseAddress)). - Een URL van de
authorizedUrlsmatrix.
Niet-geverifieerde of niet-geautoriseerde web-API-aanvragen in een app met een beveiligde standaardclient
Een app die gewoonlijk gebruikmaakt van een beveiligde standaardwaarde HttpClient , kan ook niet-geverifieerde of niet-geautoriseerde web-API-aanvragen maken door een benoemde naam HttpClientte configureren.
In het volgende voorbeeld HttpClientFactoryServiceCollectionExtensions.AddHttpClient is een extensie in Microsoft.Extensions.Http. Voeg het pakket toe aan een app die er nog niet naar verwijst.
Note
Zie de artikelen onder Pakketten installeren en beheren bij Verbruikswerkstroom voor pakketten (NuGet-documentatie)voor begeleiding bij het toevoegen van pakketten in .NET-apps. Bevestig de juiste pakketversies op NuGet.org.
In het bestand Program:
builder.Services.AddHttpClient("WebAPI.NoAuthenticationClient",
client => client.BaseAddress = new Uri("https://api.contoso.com/v1.0"));
Voor een gehoste Blazor oplossing op basis van de Blazor WebAssembly projectsjabloon wordt IWebAssemblyHostEnvironment.BaseAddress (new Uri(builder.HostEnvironment.BaseAddress)) toegewezen aan de HttpClient.BaseAddress.
De voorgaande registratie is een aanvulling op de bestaande beveiligde standaardregistratie HttpClient .
Een component maakt het HttpClient vanuit de IHttpClientFactory (Microsoft.Extensions.Http pakket) om niet-geverifieerde of niet-geautoriseerde aanvragen te doen.
@inject IHttpClientFactory ClientFactory
...
@code {
protected override async Task OnInitializedAsync()
{
var client = ClientFactory.CreateClient("WebAPI.NoAuthenticationClient");
var examples = await client.GetFromJsonAsync<ExampleType[]>(
"ExampleNoAuthentication");
...
}
}
Note
De controller in de server-API, voor het voorgaande voorbeeld, ExampleNoAuthenticationController is niet gemarkeerd met het [Authorize] kenmerk.
De beslissing om een beveiligde of een onveilige client als standaardinstantie HttpClient te gebruiken, is aan de ontwikkelaar. Een manier om deze beslissing te nemen, is rekening te houden met het aantal geauthenticeerde en niet-geauthenticeerde eindpunten waarmee de app contact maakt. Als het merendeel van de aanvragen van de app het beveiligen van API-eindpunten is, gebruikt u het geverifieerde HttpClient exemplaar als de standaardinstelling. Anders registreert u het niet-geverifieerde HttpClient exemplaar als de standaardinstelling.
Een alternatieve methode voor gebruik van de IHttpClientFactory is om een getypte client te maken voor niet-geverifieerde toegang tot anonieme eindpunten.
Aanvullende toegangstokens aanvragen
Toegangstokens kunnen handmatig worden verkregen door aan te roepen IAccessTokenProvider.RequestAccessToken. In het volgende voorbeeld is een extra bereik vereist voor een app voor de standaardwaarde HttpClient. In het MSAL-voorbeeld (Microsoft Authentication Library) wordt het bereik geconfigureerd met MsalProviderOptions:
In het bestand Program:
builder.Services.AddMsalAuthentication(options =>
{
...
options.ProviderOptions.AdditionalScopesToConsent.Add("{CUSTOM SCOPE 1}");
options.ProviderOptions.AdditionalScopesToConsent.Add("{CUSTOM SCOPE 2}");
}
De {CUSTOM SCOPE 1} en {CUSTOM SCOPE 2} plaatsaanduidingen in het vorige voorbeeld zijn aangepaste bereiken.
Note
AdditionalScopesToConsent kan geen gedelegeerde gebruikersmachtigingen voor Microsoft Graph inrichten via de toestemmingsinterface van Microsoft Entra ID wanneer een gebruiker een app voor het eerst gebruikt die is geregistreerd in Microsoft Azure. Zie Graph API gebruiken met ASP.NET Core Blazor WebAssemblyvoor meer informatie.
De IAccessTokenProvider.RequestAccessToken-methode biedt een overload waarmee een app een toegangstoken kan inrichten met een bepaalde set scopes.
In een Razor onderdeel:
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject IAccessTokenProvider TokenProvider
...
var tokenResult = await TokenProvider.RequestAccessToken(
new AccessTokenRequestOptions
{
Scopes = [ "{CUSTOM SCOPE 1}", "{CUSTOM SCOPE 2}" ]
});
if (tokenResult.TryGetToken(out var token))
{
...
}
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject IAccessTokenProvider TokenProvider
...
var tokenResult = await TokenProvider.RequestAccessToken(
new AccessTokenRequestOptions
{
Scopes = new[] { "{CUSTOM SCOPE 1}", "{CUSTOM SCOPE 2}" }
});
if (tokenResult.TryGetToken(out var token))
{
...
}
De {CUSTOM SCOPE 1} en {CUSTOM SCOPE 2} plaatsaanduidingen in het vorige voorbeeld zijn aangepaste bereiken.
AccessTokenResult.TryGetToken retourneert:
-
truemet hettokenvoor gebruik. -
falseals het token niet wordt opgehaald.
CORS (Delen van middelen over verschillende oorsprongen)
Wanneer u referenties verzendt (autorisatiecookies/headers) op CORS-aanvragen, moet de Authorization header worden toegestaan door het CORS-beleid.
Het volgende beleid bevat configuratie voor:
- Oorsprong aanvragen (
http://localhost:5000,https://localhost:5001). - Elke methode (werkwoord).
-
Content-TypeenAuthorizationkopteksten. Als u een aangepaste koptekst wilt toestaan (bijvoorbeeldx-custom-header), geeft u de koptekst weer bij het aanroepen WithHeaders. - Referenties die zijn ingesteld door JavaScript-code aan de clientzijde (
credentialseigenschap ingesteld opinclude).
app.UseCors(policy =>
policy.WithOrigins("http://localhost:5000", "https://localhost:5001")
.AllowAnyMethod()
.WithHeaders(HeaderNames.ContentType, HeaderNames.Authorization,
"x-custom-header")
.AllowCredentials());
Een gehoste Blazor oplossing op basis van de Blazor WebAssembly projectsjabloon gebruikt hetzelfde basisadres voor de client- en server-apps. De client-app HttpClient.BaseAddress is ingesteld op een URI van builder.HostEnvironment.BaseAddress. CORS-configuratie is niet vereist in de standaardconfiguratie van een gehoste Blazor oplossing. Voor aanvullende client-apps die niet worden gehost door het serverproject en die het basisadres van de server-app niet delen, is CORS-configuratie in het serverproject vereist.
Zie CORS (Cross-Origin Requests) inschakelen in ASP.NET Core en het HTTP Request Tester-onderdeel (Components/HTTPRequestTester.razor) van de voorbeeld-app voor meer informatie.
Tokenaanvraagfouten verwerken
Wanneer een enkele-pagina toepassing (SPA) een gebruiker authenticeert met behulp van OpenID Connect (OIDC), wordt de authenticatiestatus lokaal in de SPA en in de Identity Provider (IP) bijgehouden in de vorm van een sessie cookie die wordt ingesteld als gevolg van het feit dat de gebruiker zijn referenties opgeeft.
De tokens die door het IP-adres voor de gebruiker worden verzonden, zijn doorgaans gedurende korte tijd geldig, ongeveer één uur normaal, zodat de client-app regelmatig nieuwe tokens moet ophalen. Anders wordt de gebruiker afgemeld nadat de verleende tokens zijn verlopen. In de meeste gevallen kunnen OIDC-clients nieuwe tokens inrichten zonder dat de gebruiker zich opnieuw hoeft te verifiëren dankzij de verificatiestatus of sessie die binnen het IP-adres wordt bewaard.
Er zijn enkele gevallen waarin de client geen token kan ophalen zonder tussenkomst van de gebruiker, bijvoorbeeld wanneer de gebruiker zich om een of andere reden expliciet afmeldt bij het IP-adres. Dit scenario treedt op als een gebruiker zich aanmeldt https://login.microsoftonline.com en zich afmeldt. In deze scenario's weet de app niet onmiddellijk dat de gebruiker zich heeft afgemeld. Een token dat door de client wordt opgeslagen, is mogelijk niet meer geldig. De client kan ook geen nieuw token inrichten zonder tussenkomst van de gebruiker nadat het huidige token is verlopen.
Deze scenario's zijn niet specifiek voor authenticatie op basis van tokens. Ze maken deel uit van de aard van SPA's. Een SPA die cookies gebruikt, kan ook geen server-API aanroepen als de authenticatie cookie wordt verwijderd.
Wanneer een app API-aanroepen naar beveiligde resources uitvoert, moet u rekening houden met het volgende:
- Als u een nieuw toegangstoken wilt inrichten om de API aan te roepen, moet de gebruiker mogelijk opnieuw worden geverifieerd.
- Zelfs als de client een token heeft dat geldig lijkt te zijn, kan de aanroep naar de server mislukken omdat het token is ingetrokken door de gebruiker.
Wanneer de app een token aanvraagt, zijn er twee mogelijke resultaten:
- De aanvraag slaagt en de app heeft een geldig token.
- De aanvraag mislukt en de app moet de gebruiker opnieuw verifiëren om een nieuw token te verkrijgen.
Wanneer een tokenaanvraag mislukt, moet u beslissen of u een huidige status wilt opslaan voordat u een omleiding uitvoert. Er bestaan verschillende benaderingen om de status op te slaan met toenemende complexiteitsniveaus:
- Sla de huidige paginastatus op in sessieopslag. Controleer tijdens de
OnInitializedAsynclevenscyclusmethode (OnInitializedAsync) of de status kan worden hersteld voordat u doorgaat. - Voeg een queryreeksparameter toe en gebruik deze als een manier om aan te geven dat de app opnieuw moet worden gehydrateerd voor de eerder opgeslagen status.
- Voeg een queryreeksparameter toe met een unieke identifier om gegevens in sessieopslag op te slaan zonder risico van conflicten met andere items.
App-status opslaan vóór een verificatiebewerking met sessieopslag
In het volgende voorbeeld ziet u hoe u:
- Behoud de status voordat u naar de aanmeldingspagina wordt omgeleid.
- Herstel de vorige status na verificatie met behulp van een queryreeksparameter.
...
@using System.Text.Json
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject IAccessTokenProvider TokenProvider
@inject IJSRuntime JS
@inject NavigationManager Navigation
<EditForm Model="User" OnSubmit="OnSaveAsync">
<label>
First Name:
<InputText @bind-Value="User!.Name" />
</label>
<label>
Last Name:
<InputText @bind-Value="User!.LastName" />
</label>
<button type="submit">Save User</button>
</EditForm>
@code {
public Profile User { get; set; } = new Profile();
protected override async Task OnInitializedAsync()
{
var currentQuery = new Uri(Navigation.Uri).Query;
if (currentQuery.Contains("state=resumeSavingProfile"))
{
var user = await JS.InvokeAsync<string>("sessionStorage.getItem",
"resumeSavingProfile");
if (!string.IsNullOrEmpty(user))
{
User = JsonSerializer.Deserialize<Profile>(user);
}
}
}
public async Task OnSaveAsync()
{
var http = new HttpClient();
http.BaseAddress = new Uri(Navigation.BaseUri);
var resumeUri = Navigation.Uri + $"?state=resumeSavingProfile";
var tokenResult = await TokenProvider.RequestAccessToken(
new AccessTokenRequestOptions
{
ReturnUrl = resumeUri
});
if (tokenResult.TryGetToken(out var token))
{
http.DefaultRequestHeaders.Add("Authorization",
$"Bearer {token.Value}");
await http.PostAsJsonAsync("Save", User);
}
else
{
await JS.InvokeVoidAsync("sessionStorage.setItem",
"resumeSavingProfile", JsonSerializer.Serialize(User));
Navigation.NavigateTo(tokenResult.InteractiveRequestUrl);
}
}
public class Profile
{
public string? FirstName { get; set; }
public string? LastName { get; set; }
}
}
App-status opslaan vóór een verificatiebewerking met sessieopslag en een statuscontainer
Tijdens een verificatiebewerking zijn er gevallen waarin u de app-status wilt opslaan voordat de browser wordt omgeleid naar het IP-adres. Dit kan het geval zijn wanneer u een statuscontainer gebruikt en de status wilt herstellen nadat de verificatie is geslaagd. U kunt een aangepast verificatiestatusobject gebruiken om de app-specifieke status of een verwijzing ernaar te behouden en die status te herstellen nadat de verificatiebewerking is voltooid. In het volgende voorbeeld ziet u de benadering.
Er wordt een statuscontainerklasse gemaakt in de app met eigenschappen voor het opslaan van de statuswaarden van de app. In het volgende voorbeeld wordt de container gebruikt om de tellerwaarde van het onderdeel () van de standaardprojectsjabloonBlazorCounter teCounter.razor behouden. Methoden voor het serialiseren en deserialiseren van de container zijn gebaseerd op System.Text.Json.
using System.Text.Json;
public class StateContainer
{
public int CounterValue { get; set; }
public string GetStateForLocalStorage() => JsonSerializer.Serialize(this);
public void SetStateFromLocalStorage(string locallyStoredState)
{
var deserializedState =
JsonSerializer.Deserialize<StateContainer>(locallyStoredState);
CounterValue = deserializedState.CounterValue;
}
}
Het Counter onderdeel gebruikt de statuscontainer om de currentCount waarde buiten het onderdeel te behouden:
@page "/counter"
@inject StateContainer State
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
protected override void OnInitialized()
{
if (State.CounterValue > 0)
{
currentCount = State.CounterValue;
}
}
private void IncrementCount()
{
currentCount++;
State.CounterValue = currentCount;
}
}
Maak een ApplicationAuthenticationState van RemoteAuthenticationState. Geef een Id eigenschap op die fungeert als een id voor de lokaal opgeslagen status.
ApplicationAuthenticationState.cs:
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
public class ApplicationAuthenticationState : RemoteAuthenticationState
{
public string? Id { get; set; }
}
Het Authentication onderdeel (Authentication.razor) slaat de status van de app op en herstelt deze met behulp van lokale sessieopslag met de StateContainer serialisatie- en deserialisatiemethoden, GetStateForLocalStorage en SetStateFromLocalStorage:
@page "/authentication/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject IJSRuntime JS
@inject StateContainer State
<RemoteAuthenticatorViewCore Action="Action"
TAuthenticationState="ApplicationAuthenticationState"
AuthenticationState="AuthenticationState"
OnLogInSucceeded="RestoreState"
OnLogOutSucceeded="RestoreState" />
@code {
[Parameter]
public string? Action { get; set; }
public ApplicationAuthenticationState AuthenticationState { get; set; } =
new ApplicationAuthenticationState();
protected override async Task OnInitializedAsync()
{
if (RemoteAuthenticationActions.IsAction(RemoteAuthenticationActions.LogIn,
Action) ||
RemoteAuthenticationActions.IsAction(RemoteAuthenticationActions.LogOut,
Action))
{
AuthenticationState.Id = Guid.NewGuid().ToString();
await JS.InvokeVoidAsync("sessionStorage.setItem",
AuthenticationState.Id, State.GetStateForLocalStorage());
}
}
private async Task RestoreState(ApplicationAuthenticationState state)
{
if (state.Id != null)
{
var locallyStoredState = await JS.InvokeAsync<string>(
"sessionStorage.getItem", state.Id);
if (locallyStoredState != null)
{
State.SetStateFromLocalStorage(locallyStoredState);
await JS.InvokeVoidAsync("sessionStorage.removeItem", state.Id);
}
}
}
}
In dit voorbeeld wordt Microsoft Entra (ME-ID) gebruikt voor verificatie. In het bestand Program:
- Het
ApplicationAuthenticationStateis geconfigureerd als het type Microsoft Authentication Library (MSAL)RemoteAuthenticationState. - De staatcontainer wordt geregistreerd in de servicecontainer.
builder.Services.AddMsalAuthentication<ApplicationAuthenticationState>(options =>
{
builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
});
builder.Services.AddSingleton<StateContainer>();
App-routes aanpassen
De Microsoft.AspNetCore.Components.WebAssembly.Authentication bibliotheek gebruikt de routes die worden weergegeven in de volgende tabel voor het weergeven van verschillende verificatiestatussen.
| Route | Purpose |
|---|---|
authentication/login |
Hiermee wordt een aanmeldingsbewerking geactiveerd. |
authentication/login-callback |
Verwerkt het resultaat van een aanmeldingsbewerking. |
authentication/login-failed |
Geeft foutberichten weer wanneer de aanmeldingsbewerking om een of andere reden mislukt. |
authentication/logout |
Hiermee wordt een afmeldingsbewerking geactiveerd. |
authentication/logout-callback |
Verwerkt het resultaat van een afmeldingsbewerking. |
authentication/logout-failed |
Geeft foutberichten weer wanneer de afmeldingsbewerking om een of andere reden mislukt. |
authentication/logged-out |
Geeft aan dat de gebruiker zich heeft afgemeld. |
authentication/profile |
Hiermee wordt een bewerking geactiveerd om het gebruikersprofiel te bewerken. |
authentication/register |
Hiermee wordt een bewerking geactiveerd om een nieuwe gebruiker te registreren. |
De routes die in de voorgaande tabel worden weergegeven, kunnen worden geconfigureerd via RemoteAuthenticationOptions<TRemoteAuthenticationProviderOptions>.AuthenticationPaths. Wanneer u opties instelt om aangepaste routes te bieden, controleert u of de app een route heeft die elk pad verwerkt.
In het volgende voorbeeld worden alle paden voorafgegaan door /security.
Authentication onderdeel (Authentication.razor):
@page "/security/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
<RemoteAuthenticatorView Action="@Action" />
@code{
[Parameter]
public string? Action { get; set; }
}
@page "/security/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
<RemoteAuthenticatorView Action="@Action" />
@code{
[Parameter]
public string Action { get; set; }
}
In het bestand Program:
builder.Services.AddApiAuthorization(options => {
options.AuthenticationPaths.LogInPath = "security/login";
options.AuthenticationPaths.LogInCallbackPath = "security/login-callback";
options.AuthenticationPaths.LogInFailedPath = "security/login-failed";
options.AuthenticationPaths.LogOutPath = "security/logout";
options.AuthenticationPaths.LogOutCallbackPath = "security/logout-callback";
options.AuthenticationPaths.LogOutFailedPath = "security/logout-failed";
options.AuthenticationPaths.LogOutSucceededPath = "security/logged-out";
options.AuthenticationPaths.ProfilePath = "security/profile";
options.AuthenticationPaths.RegisterPath = "security/register";
});
Als de vereiste voor volledig verschillende paden aanroept, stelt u de routes in zoals eerder beschreven en geeft u de RemoteAuthenticatorView met een expliciete actieparameter weer:
@page "/register"
<RemoteAuthenticatorView Action="RemoteAuthenticationActions.Register" />
U kunt de gebruikersinterface opsplitsen in verschillende pagina's als u dit wilt doen.
De gebruikersinterface voor verificatie aanpassen
RemoteAuthenticatorView bevat een standaardset ui-fragmenten voor elke verificatiestatus. Elke status kan worden aangepast door een aangepaste RenderFragmentdoor te geven. Als u de weergegeven tekst tijdens het eerste aanmeldingsproces wilt aanpassen, kunt u de RemoteAuthenticatorView tekst als volgt wijzigen.
Authentication onderdeel (Authentication.razor):
@page "/security/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
<RemoteAuthenticatorView Action="@Action">
<LoggingIn>
You are about to be redirected to https://login.microsoftonline.com.
</LoggingIn>
</RemoteAuthenticatorView>
@code{
[Parameter]
public string? Action { get; set; }
}
@page "/security/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
<RemoteAuthenticatorView Action="@Action">
<LoggingIn>
You are about to be redirected to https://login.microsoftonline.com.
</LoggingIn>
</RemoteAuthenticatorView>
@code{
[Parameter]
public string Action { get; set; }
}
Het RemoteAuthenticatorView bevat één fragment dat kan worden gebruikt per verificatieroute die wordt weergegeven in de volgende tabel.
| Route | Fragment |
|---|---|
authentication/login |
<LoggingIn> |
authentication/login-callback |
<CompletingLoggingIn> |
authentication/login-failed |
<LogInFailed> |
authentication/logout |
<LogOut> |
authentication/logout-callback |
<CompletingLogOut> |
authentication/logout-failed |
<LogOutFailed> |
authentication/logged-out |
<LogOutSucceeded> |
authentication/profile |
<UserProfile> |
authentication/register |
<Registering> |
De gebruiker aanpassen
Gebruikers die zijn gebonden aan de app, kunnen worden aangepast.
De gebruiker aanpassen met een payloadclaim
In het volgende voorbeeld ontvangen de geverifieerde gebruikers van de app een amr claim voor elk van de verificatiemethoden van de gebruiker. De amr claim identificeert hoe het onderwerp van het token is geauthenticeerd in de payload-claims van Microsoft Identity Platform v1.0. In het voorbeeld wordt een aangepaste gebruikersaccountklasse op basis van RemoteUserAccount gebruikt.
Maak een klasse die de RemoteUserAccount klasse uitbreidt. In het volgende voorbeeld wordt de eigenschap AuthenticationMethod ingesteld op de array van JSON-eigenschapswaarden van de gebruiker amr.
AuthenticationMethod wordt automatisch ingevuld door het framework wanneer de gebruiker wordt geverifieerd.
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
public class CustomUserAccount : RemoteUserAccount
{
[JsonPropertyName("amr")]
public string[]? AuthenticationMethod { get; set; }
}
Maak een factory die AccountClaimsPrincipalFactory<TAccount> uitbreidt om claims te creëren op basis van de verificatiemethoden van de gebruiker die zijn opgeslagen in CustomUserAccount.AuthenticationMethod:
using System.Security.Claims;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;
public class CustomAccountFactory(NavigationManager navigation,
IAccessTokenProviderAccessor accessor)
: AccountClaimsPrincipalFactory<CustomUserAccount>(accessor)
{
public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
CustomUserAccount account, RemoteAuthenticationUserOptions options)
{
var initialUser = await base.CreateUserAsync(account, options);
if (initialUser.Identity != null && initialUser.Identity.IsAuthenticated)
{
var userIdentity = (ClaimsIdentity)initialUser.Identity;
if (account.AuthenticationMethod is not null)
{
foreach (var value in account.AuthenticationMethod)
{
userIdentity.AddClaim(new Claim("amr", value));
}
}
}
return initialUser;
}
}
Registreer de CustomAccountFactory verificatieprovider die wordt gebruikt. Een van de volgende registraties is geldig:
-
using Microsoft.AspNetCore.Components.WebAssembly.Authentication; ... builder.Services.AddOidcAuthentication<RemoteAuthenticationState, CustomUserAccount>(options => { ... }) .AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, CustomUserAccount, CustomAccountFactory>(); -
using Microsoft.AspNetCore.Components.WebAssembly.Authentication; ... builder.Services.AddMsalAuthentication<RemoteAuthenticationState, CustomUserAccount>(options => { ... }) .AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, CustomUserAccount, CustomAccountFactory>(); -
using Microsoft.AspNetCore.Components.WebAssembly.Authentication; ... builder.Services.AddApiAuthorization<RemoteAuthenticationState, CustomUserAccount>(options => { ... }) .AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, CustomUserAccount, CustomAccountFactory>();
ME-ID beveiligingsgroepen en -rollen met een aangepaste gebruikersaccountklasse
Zie ASP.NET Core Blazor WebAssembly met Microsoft Entra ID-groepen en -rollen voor een extra voorbeeld dat werkt met ME-ID beveiligingsgroepen en ME-ID Administrator-rollen en een aangepaste gebruikersaccountklasse.
Prerendering met verificatie
Het vooraf weergeven van inhoud waarvoor verificatie en autorisatie is vereist, wordt momenteel niet ondersteund. Nadat u de richtlijnen in een van de onderwerpen over beveiligings-apps Blazor WebAssembly hebt gevolgd, gebruikt u de volgende instructies om een app te maken die:
- Prerendert paden waarvoor autorisatie niet vereist is.
- Er worden geen paden vooraf opgegeven waarvoor autorisatie is vereist.
Voor het Client-bestand van het Program-project, breng gemeenschappelijke serviceregistraties onder in een aparte methode (maak bijvoorbeeld een ConfigureCommonServices-methode in het Client-project). Algemene services zijn services die de ontwikkelaar registreert voor gebruik door zowel de client- als serverprojecten.
public static void ConfigureCommonServices(IServiceCollection services)
{
services.Add...;
}
In het bestand Program:
var builder = WebAssemblyHostBuilder.CreateDefault(args);
...
builder.Services.AddScoped( ... );
ConfigureCommonServices(builder.Services);
await builder.Build().RunAsync();
Registreer de volgende aanvullende services in het Server bestand van het Program project en roep ConfigureCommonServices aan:
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Server;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
...
builder.Services.AddRazorPages();
builder.Services.TryAddScoped<AuthenticationStateProvider,
ServerAuthenticationStateProvider>();
Client.Program.ConfigureCommonServices(services);
Registreer in de Server-methode van het Startup.ConfigureServices-project de volgende aanvullende services en roep ConfigureCommonServices deze aan:
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Server;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
public void ConfigureServices(IServiceCollection services)
{
...
services.AddRazorPages();
services.AddScoped<AuthenticationStateProvider,
ServerAuthenticationStateProvider>();
services.AddScoped<SignOutSessionStateManager>();
Client.Program.ConfigureCommonServices(services);
}
Zie Blazor voor meer informatie over de ServerAuthenticationStateProvider frameworkserververificatieprovider (Blazor).
Vervang in het Server-project's Pages/_Host.cshtml-bestand de Component Tag Helper (<component ... />) door het volgende:
<div id="app">
@if (HttpContext.Request.Path.StartsWithSegments("/authentication"))
{
<component type="typeof({CLIENT APP ASSEMBLY NAME}.App)"
render-mode="WebAssembly" />
}
else
{
<component type="typeof({CLIENT APP ASSEMBLY NAME}.App)"
render-mode="WebAssemblyPrerendered" />
}
</div>
In het voorgaande voorbeeld:
- De
{CLIENT APP ASSEMBLY NAME}plaatsaanduiding is de assemblynaam van de client-app (bijvoorbeeldBlazorSample.Client). - De voorwaardelijke controle voor het
/authenticationpadsegment:- Vermijd prerendering (
render-mode="WebAssembly") voor verificatiepaden. - Prerenders (
render-mode="WebAssemblyPrerendered") voor niet-authenticatiepaden.
- Vermijd prerendering (
Opties voor gehoste apps en aanmeldingsproviders van derden
Bij het verifiëren en autoriseren van een gehoste Blazor WebAssembly app met een externe provider zijn er verschillende opties beschikbaar voor het verifiëren van de gebruiker. Welke u kiest, is afhankelijk van uw scenario.
Voor meer informatie, zie Aanvullende claims en tokens van externe providers opslaan in ASP.NET Core.
Gebruikers verifiëren om alleen beveiligde API's van derden aan te roepen
Authenticeer de gebruiker met een client-side OAuth-stroom bij de derde-partij API-provider.
builder.services.AddOidcAuthentication(options => { ... });
In dit scenario:
- De server die als host fungeert voor de app speelt geen rol.
- API's op de server kunnen niet worden beveiligd.
- De app kan alleen beveiligde API's van derden aanroepen.
Gebruikers verifiëren met een externe provider en beveiligde API's aanroepen op de hostserver en de derde partij
Configureer Identity met een externe aanmeldingsprovider. Haal de tokens op die vereist zijn voor API-toegang van derden en sla ze op.
Wanneer een gebruiker zich aanmeldt, Identity verzamelt u toegangs- en vernieuwingstokens als onderdeel van het verificatieproces. Op dat moment zijn er een aantal methoden beschikbaar voor het maken van API-aanroepen naar API's van derden.
Een servertoegangstoken gebruiken om het toegangstoken van derden op te halen
Gebruik het toegangstoken dat is gegenereerd op de server om het toegangstoken van derden op te halen uit een server-API-eindpunt. Gebruik daar het toegangstoken van derden om API-resources van derden rechtstreeks vanuit Identity de client aan te roepen.
We raden deze methode niet aan. Voor deze aanpak moet het toegangstoken van derden worden behandeld alsof het is gegenereerd voor een openbare client. In OAuth-termen heeft de openbare app geen clientgeheim, omdat het niet kan worden vertrouwd om geheimen veilig op te slaan en het toegangstoken wordt geproduceerd voor een vertrouwelijke client. Een vertrouwelijke client is een client met een clientgeheim en wordt ervan uitgegaan dat geheimen veilig kunnen worden opgeslagen.
- Het toegangstoken van een derde partij kan extra rechten krijgen om gevoelige bewerkingen uit te voeren, op basis van het feit dat de derde partij het token heeft uitgegeven voor een meer vertrouwde cliënt.
- Op dezelfde manier mogen vernieuwingstokens niet worden uitgegeven aan een client die niet wordt vertrouwd, omdat dit de client onbeperkte toegang geeft, tenzij er andere beperkingen zijn ingesteld.
API-aanroepen uitvoeren van de client naar de server-API om API's van derden aan te roepen
Maak een API-aanroep van de client naar de server-API. Haal het toegangstoken voor de API-resource van derden op van de server en voer de noodzakelijke oproep uit.
We raden deze aanpak aan. Hoewel deze aanpak een extra netwerkhop via de server vereist om een API van derden aan te roepen, resulteert dit uiteindelijk in een veiligere ervaring:
- De server kan vernieuwingstokens opslaan en ervoor zorgen dat de app geen toegang meer heeft tot resources van derden.
- De app kan geen toegangstokens lekken van de server die mogelijk meer gevoelige machtigingen bevat.
OpenID Connect -eindpunten (OIDC) v2.0 gebruiken
De verificatiebibliotheek en Blazor projectsjablonen maken gebruik van OpenID Connect -eindpunten (OIDC) v1.0. Als u een v2.0-eindpunt wilt gebruiken, configureert u de JWT Bearer-optie JwtBearerOptions.Authority . In het volgende voorbeeld wordt ME-ID geconfigureerd voor v2.0 door een v2.0 segment toe te voegen aan de Authority eigenschap:
using Microsoft.AspNetCore.Authentication.JwtBearer;
...
builder.Services.Configure<JwtBearerOptions>(
JwtBearerDefaults.AuthenticationScheme,
options =>
{
options.Authority += "/v2.0";
});
U kunt de instelling ook maken in het app-instellingenbestand (appsettings.json):
{
"Local": {
"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 JwtBearerOptions of in het app-instellingenbestand (appsettings.json) met de Authority sleutel.
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.
GRPC configureren en gebruiken in onderdelen
Een app configureren Blazor WebAssembly voor het gebruik van het ASP.NET Core gRPC-framework:
- Schakel gRPC-Web in op de server. Zie gRPC-Web in ASP.NET Core gRPC-apps voor meer informatie.
- Registreer gRPC-services voor de berichthandler van de app. In het volgende voorbeeld wordt de autorisatieberichthandler van de app geconfigureerd voor het gebruik van de
GreeterClientservice uit de gRPC-zelfstudie (hetProgrambestand).
Note
Prerendering is standaard ingeschakeld in Blazor Web Apps, dus u moet eerst rekening houden met de rendering van het onderdeel vanaf de server en vervolgens vanaf de client. Elke vooraf samengestelde status moet naar de client stromen, zodat deze opnieuw kan worden gebruikt. Zie ASP.NET Core vooraf samengestelde statuspersistentieBlazor voor meer informatie.
Note
Prerendering is standaard ingeschakeld in gehoste Blazor WebAssembly apps, dus u moet eerst rekening houden met de rendering van het onderdeel vanaf de server en vervolgens vanaf de client. Elke vooraf samengestelde status moet naar de client stromen, zodat deze opnieuw kan worden gebruikt. Zie Integreren ASP.NET Core-onderdelen Razor met MVC of Razor Pages in gehoste Blazor WebAssembly oplossingen voor meer informatie.
using System.Net.Http;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Grpc.Net.Client;
using Grpc.Net.Client.Web;
...
builder.Services.AddScoped(sp =>
{
var baseAddressMessageHandler =
sp.GetRequiredService<BaseAddressAuthorizationMessageHandler>();
baseAddressMessageHandler.InnerHandler = new HttpClientHandler();
var grpcWebHandler =
new GrpcWebHandler(GrpcWebMode.GrpcWeb, baseAddressMessageHandler);
var channel = GrpcChannel.ForAddress(builder.HostEnvironment.BaseAddress,
new GrpcChannelOptions { HttpHandler = grpcWebHandler });
return new Greeter.GreeterClient(channel);
});
Een onderdeel in de client-app kan gRPC-aanroepen uitvoeren met behulp van de gRPC-client (Grpc.razor):
@page "/grpc"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]
@inject Greeter.GreeterClient GreeterClient
<h1>Invoke gRPC service</h1>
<p>
<input @bind="name" placeholder="Type your name" />
<button @onclick="GetGreeting" class="btn btn-primary">Call gRPC service</button>
</p>
Server response: <strong>@serverResponse</strong>
@code {
private string name = "Bert";
private string? serverResponse;
private async Task GetGreeting()
{
try
{
var request = new HelloRequest { Name = name };
var reply = await GreeterClient.SayHelloAsync(request);
serverResponse = reply.Message;
}
catch (Grpc.Core.RpcException ex)
when (ex.Status.DebugException is
AccessTokenNotAvailableException tokenEx)
{
tokenEx.Redirect();
}
}
}
Als u de Status.DebugException eigenschap wilt gebruiken, gebruikt u Grpc.Net.Client versie 2.30.0 of hoger.
Zie gRPC-Web in ASP.NET Core gRPC-apps voor meer informatie.
AuthenticationService De implementatie vervangen
In de volgende subsecties wordt uitgelegd hoe u deze kunt vervangen:
- Elke JavaScript-implementatie
AuthenticationService. - De Microsoft Authentication Library voor JavaScript (
MSAL.js).
Een JavaScript-implementatie AuthenticationService vervangen
Maak een JavaScript-bibliotheek om uw aangepaste verificatiegegevens af te handelen.
Warning
De richtlijnen in deze sectie zijn een implementatiedetail van de standaard RemoteAuthenticationService<TRemoteAuthenticationState,TAccount,TProviderOptions>. De TypeScript-code in deze sectie is specifiek van toepassing op ASP.NET Core in .NET 7 en kan zonder kennisgeving worden gewijzigd in toekomstige releases van ASP.NET Core.
// .NET makes calls to an AuthenticationService object in the Window.
declare global {
interface Window { AuthenticationService: AuthenticationService }
}
export interface AuthenticationService {
// Init is called to initialize the AuthenticationService.
public static init(settings: UserManagerSettings & AuthorizeServiceSettings, logger: any) : Promise<void>;
// Gets the currently authenticated user.
public static getUser() : Promise<{[key: string] : string }>;
// Tries to get an access token silently.
public static getAccessToken(options: AccessTokenRequestOptions) : Promise<AccessTokenResult>;
// Tries to sign in the user or get an access token interactively.
public static signIn(context: AuthenticationContext) : Promise<AuthenticationResult>;
// Handles the sign-in process when a redirect is used.
public static async completeSignIn(url: string) : Promise<AuthenticationResult>;
// Signs the user out.
public static signOut(context: AuthenticationContext) : Promise<AuthenticationResult>;
// Handles the signout callback when a redirect is used.
public static async completeSignOut(url: string) : Promise<AuthenticationResult>;
}
// The rest of these interfaces match their C# definitions.
export interface AccessTokenRequestOptions {
scopes: string[];
returnUrl: string;
}
export interface AccessTokenResult {
status: AccessTokenResultStatus;
token?: AccessToken;
}
export interface AccessToken {
value: string;
expires: Date;
grantedScopes: string[];
}
export enum AccessTokenResultStatus {
Success = 'Success',
RequiresRedirect = 'RequiresRedirect'
}
export enum AuthenticationResultStatus {
Redirect = 'Redirect',
Success = 'Success',
Failure = 'Failure',
OperationCompleted = 'OperationCompleted'
};
export interface AuthenticationResult {
status: AuthenticationResultStatus;
state?: unknown;
message?: string;
}
export interface AuthenticationContext {
state?: unknown;
interactiveRequest: InteractiveAuthenticationRequest;
}
export interface InteractiveAuthenticationRequest {
scopes?: string[];
additionalRequestParameters?: { [key: string]: any };
};
U kunt de bibliotheek importeren door de oorspronkelijke <script> tag te verwijderen en een <script> tag toe te voegen waarmee de aangepaste bibliotheek wordt geladen. In het volgende voorbeeld ziet u hoe u de standaardtag vervangt door een tag <script> waarmee een bibliotheek met de naam CustomAuthenticationService.js uit de wwwroot/js map wordt geladen.
Vóór wwwroot/index.html het Blazor script (_framework/blazor.webassembly.js) binnen de afsluitende </body> tag:
- <script src="_content/Microsoft.Authentication.WebAssembly.Msal/AuthenticationService.js"></script>
+ <script src="js/CustomAuthenticationService.js"></script>
Zie de AuthenticationService.ts GitHub-opslagplaats voor meer informatiedotnet/aspnetcore.
Note
Documentatiekoppelingen naar .NET-referentiebron laden meestal de standaardbranch van de opslagplaats, die de huidige ontwikkeling vertegenwoordigt voor de volgende release van .NET. Als u een tag voor een specifieke release wilt selecteren, gebruikt u de Switch branches of tags vervolgkeuzelijst. Zie Een versietag selecteren van ASP.NET Core-broncode (dotnet/AspNetCore.Docs #26205)voor meer informatie.
Vervang de Microsoft Authentication Library voor JavaScript (MSAL.js)
Als voor een app een aangepaste versie van de Microsoft Authentication Library voor JavaScript (MSAL.js)is vereist, moet u de volgende stappen uitvoeren:
- Controleer of het systeem beschikt over de nieuwste .NET SDK voor ontwikkelaars of dat u de nieuwste ontwikkelaars-SDK ophaalt en installeert via .NET SDK: Installatieprogramma's en binaire bestanden. De configuratie van interne NuGet-feeds is niet vereist voor dit scenario.
- Stel de
dotnet/aspnetcoreGitHub-opslagplaats in voor de ontwikkeling volgens de documentatie van Build ASP.NET Core van bron. Fork en kloon het of download een ZIP-archief van dedotnet/aspnetcoreGitHub repository. - Open het
src/Components/WebAssembly/Authentication.Msal/src/Interop/package.jsonbestand en stel de gewenste versie van@azure/msal-browser. Ga naar de@azure/msal-browsernpm-website en selecteer het tabblad Versies voor een lijst met uitgebrachte versies. - Bouw het
Authentication.Msalproject in desrc/Components/WebAssembly/Authentication.Msal/srcmap met deyarn buildopdracht in een opdrachtshell. - Als de app gecomprimeerde assets (Brotli/Gzip) gebruikt, comprimeert u het
Interop/dist/Release/AuthenticationService.jsbestand. - Kopieer het
AuthenticationService.jsbestand en de gecomprimeerde versies (.br/.gz) van het bestand, indien geproduceerd, van deInterop/dist/Releasemap naar de map vanpublish/wwwroot/_content/Microsoft.Authentication.WebAssembly.Msalde app in de gepubliceerde assets van de app.
Aangepaste provideropties doorgeven
Definieer een klasse voor het doorgeven van de gegevens aan de onderliggende JavaScript-bibliotheek.
Important
De structuur van de klasse moet overeenkomen met wat de bibliotheek verwacht wanneer de JSON wordt geserialiseerd met System.Text.Json.
In het volgende voorbeeld ziet u een ProviderOptions klasse met JsonPropertyName kenmerken die overeenkomen met de verwachtingen van een hypothetische aangepaste providerbibliotheek:
public class ProviderOptions
{
public string? Authority { get; set; }
public string? MetadataUrl { get; set; }
[JsonPropertyName("client_id")]
public string? ClientId { get; set; }
public IList<string> DefaultScopes { get; set; } = [ "openid", "profile" ];
[JsonPropertyName("redirect_uri")]
public string? RedirectUri { get; set; }
[JsonPropertyName("post_logout_redirect_uri")]
public string? PostLogoutRedirectUri { get; set; }
[JsonPropertyName("response_type")]
public string? ResponseType { get; set; }
[JsonPropertyName("response_mode")]
public string? ResponseMode { get; set; }
}
Registreer de provideropties in het DI-systeem en configureer de juiste waarden:
builder.Services.AddRemoteAuthentication<RemoteAuthenticationState, RemoteUserAccount,
ProviderOptions>(options => {
options.ProviderOptions.Authority = "...";
options.ProviderOptions.MetadataUrl = "...";
options.ProviderOptions.ClientId = "...";
options.ProviderOptions.DefaultScopes = [ "openid", "profile", "myApi" ];
options.ProviderOptions.RedirectUri = "https://localhost:5001/authentication/login-callback";
options.ProviderOptions.PostLogoutRedirectUri = "https://localhost:5001/authentication/logout-callback";
options.ProviderOptions.ResponseType = "...";
options.ProviderOptions.ResponseMode = "...";
});
In het voorgaande voorbeeld worden omleidings-URI's ingesteld met gewone letterlijke tekenreeksen. De volgende alternatieven zijn beschikbaar:
TryCreate met behulp van IWebAssemblyHostEnvironment.BaseAddress:
Uri.TryCreate( $"{builder.HostEnvironment.BaseAddress}authentication/login-callback", UriKind.Absolute, out var redirectUri); options.RedirectUri = redirectUri;-
options.RedirectUri = builder.Configuration["RedirectUri"];wwwroot/appsettings.json:{ "RedirectUri": "https://localhost:5001/authentication/login-callback" }