Condividi tramite


Autenticazione e autorizzazione per ASP.NET Core Blazor

Nota

Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 9 di questo articolo.

Avviso

Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere i criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 9 di questo articolo.

Importante

Queste informazioni si riferiscono a un prodotto non definitive che può essere modificato in modo sostanziale prima che venga rilasciato commercialmente. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.

Per la versione corrente, vedere la versione .NET 9 di questo articolo.

Questo articolo descrive il supporto di ASP.NET Core per la configurazione e la gestione della sicurezza nelle app Blazor.

Blazor usa i meccanismi di autenticazione di base di ASP.NET esistenti per stabilire l'identità dell'utente. Il meccanismo esatto dipende dal modo in cui l'app Blazor è ospitata, lato server o lato client.

Gli scenari di sicurezza variano tra il codice di autorizzazione che esegue il lato server e il lato client nelle Blazor app. Per il codice di autorizzazione eseguito nel server, i controlli di autorizzazione sono in grado di applicare le regole di accesso per le aree dell'app e dei componenti. Poiché l'esecuzione del codice sul lato client può essere manomessa, il codice di autorizzazione in esecuzione nel client non può essere considerato attendibile per applicare assolutamente le regole di accesso o controllare la visualizzazione del contenuto lato client.

Se l'imposizione delle regole di autorizzazione deve essere garantita, non implementare i controlli di autorizzazione nel codice lato client. Creare un Blazor Web App che si basa solo sul rendering lato server (SSR) per i controlli di autorizzazione e l'applicazione delle regole.

Se l'imposizione delle regole di autorizzazione e la sicurezza dei dati e del codice devono essere garantiti, non sviluppare un'app sul lato client. Creare un'app Blazor Server .

Razor Le convenzioni di autorizzazione delle pagine non si applicano ai componenti instradabili Razor . Se un componente non instradabile Razor è incorporato in una pagina di un'app Razor Pages, le convenzioni di autorizzazione della pagina influiscono indirettamente sul Razor componente insieme al resto del contenuto della pagina.

ASP.NET Core Identity è progettato per funzionare nel contesto della comunicazione di richiesta e risposta HTTP, che in genere non è il modello di comunicazione client-server dell'app Blazor . Le app ASP.NET Core che usano ASP.NET Core Identity per la gestione utenti devono usare Razor Pages anziché componenti Razor per l'interfaccia utente correlata a Identity, ad esempio registrazione utente, accesso, disconnessione e altre attività di gestione utenti. La compilazione di Razor componenti che gestiscono Identity direttamente le attività è possibile per diversi scenari, ma non è consigliata o supportata da Microsoft.

Le astrazioni ASP.NET Core, come SignInManager<TUser> e UserManager<TUser>, non sono supportate nei componenti Razor. Per ulteriori informazioni sull'uso di ASP.NET Core Identity con Blazor, vedere Scaffold ASP.NET Core Identity in un'app Blazor server.

Nota

Gli esempi di codice in questo articolo adottano tipi di riferimento nullable (NRT) e l'analisi statica dello stato null del compilatore .NET, supportati in ASP.NET Core in .NET 6 o versione successiva. Quando la destinazione è ASP.NET Core 5.0 o versioni precedenti, rimuovere la designazione di tipo Null (?) dagli esempi in questo articolo.

Mantenere in modo sicuro dati e credenziali sensibili

Non archiviare segreti dell'app, stringhe di connessione, credenziali, password, numeri di identificazione personale (PIN), codice .NET/C# privato o chiavi/token privati nel codice lato client, che è sempre non sicuro. Il codice lato Blazor client deve accedere a servizi e database sicuri tramite un'API Web sicura che tu controlli.

Negli ambienti di test/gestione temporanea e produzione, il codice lato Blazor server e le API Web devono usare flussi di autenticazione sicuri che evitano di mantenere le credenziali all'interno del codice del progetto o dei file di configurazione. Al di fuori dei test di sviluppo locali, è consigliabile evitare l'uso di variabili di ambiente per archiviare i dati sensibili, perché le variabili di ambiente non sono l'approccio più sicuro. Per i test di sviluppo locali, lo strumento Secret Manager è consigliato per proteggere i dati sensibili. Per ulteriori informazioni, vedi le seguenti risorse:

Per lo sviluppo e il test locali sul lato client e sul lato server, usare lo strumento Secret Manager per proteggere le credenziali sensibili.

Identità gestite per i servizi di Microsoft Azure

Per i servizi di Microsoft Azure, è consigliabile usare le identità gestite. Le identità gestite eseguono l'autenticazione sicura ai servizi di Azure senza archiviare le credenziali nel codice dell'app. Per ulteriori informazioni, vedi le seguenti risorse:

Supporto antiforgerato

Il Blazor modello:

Il componente AntiforgeryToken renderizza un token antiforgery come campo nascosto e questo componente viene aggiunto automaticamente alle istanze del form (EditForm). Per ulteriori informazioni, vedere Panoramica sui moduli di ASP.NET Core.

Il servizio AntiforgeryStateProvider fornisce l'accesso a un token antifalsificazione associato alla sessione corrente. Iniettare il servizio e chiamare il metodo GetAntiforgeryToken() per ottenere il AntiforgeryRequestToken corrente. Per altre informazioni, vedere Chiamare un'API Web da un'app ASP.NET CoreBlazor.

Blazor archivia i token di richiesta nello stato del componente, che garantisce che i token antiforgery siano disponibili per i componenti interattivi, anche quando non hanno accesso alla richiesta.

Nota

La mitigazione antiforgery è necessaria solo quando si inviano i dati del modulo al server codificati come application/x-www-form-urlencoded, multipart/form-datao text/plain poiché sono gli unici tipi di modulo validi.

Per ulteriori informazioni, vedi le seguenti risorse:

Autenticazione Blazor server-side

Le app lato Blazor server vengono configurate per la sicurezza nello stesso modo delle app ASP.NET Core. Per altre informazioni, vedere gli articoli in ASP.NET Argomenti sulla sicurezza di base.

Il contesto di autenticazione viene stabilito solo all'avvio dell'app, ovvero quando l'app si connette per la prima volta al WebSocket tramite una SignalR connessione con il client. L'autenticazione può essere basata su un cookie o su un altro token di connessione, ma l'autenticazione viene gestita tramite l'hub SignalR e interamente all'interno del circuito. Il contesto di autenticazione viene mantenuto per la durata del circuito. Le app riconvalidano periodicamente lo stato di autenticazione dell'utente ogni 30 minuti.

Se l'app deve acquisire utenti per servizi personalizzati o reagire agli aggiornamenti dell'utente, vedere ASP.NET Core lato server e scenari di sicurezza aggiuntivi.

Blazor si differenzia dalle tradizionali applicazioni web sottoposte a rendering del server che effettuano nuove richieste HTTP con cookie in ogni navigazione di pagina. L'autenticazione viene verificata durante gli eventi di navigazione. Tuttavia, i cookie non sono coinvolti. I cookie vengono inviati solo quando si effettua una richiesta HTTP a un server, che non avviene quando l'utente si sposta in un'app Blazor . Durante la navigazione, lo stato di autenticazione dell'utente viene controllato all'interno del Blazor circuito, che è possibile aggiornare in qualsiasi momento sul server usando l'astrazioneRevalidatingAuthenticationStateProvider.

Importante

L'implementazione di un personalizzato NavigationManager per ottenere la convalida dell'autenticazione durante la navigazione non è consigliata. Se l'app deve eseguire la logica dello stato di autenticazione personalizzata durante la navigazione, usare un componente personalizzato AuthenticationStateProvider.

Nota

Gli esempi di codice in questo articolo adottano tipi di riferimento nullable (NRT) e l'analisi statica dello stato null del compilatore .NET, supportati in ASP.NET Core in .NET 6 o versione successiva. Quando la destinazione è ASP.NET Core 5.0 o versioni precedenti, rimuovere la designazione di tipo Null (?) dagli esempi in questo articolo.

Il servizio predefinito o personalizzato AuthenticationStateProvider ottiene i dati dello stato di autenticazione da ASP.NET Core.HttpContext.User Questo è il modo in cui lo stato di autenticazione si integra con i meccanismi di autenticazione ASP.NET Core esistenti.

Per ulteriori informazioni sull'autenticazione lato server, vedere ASP.NET Core autenticazione e autorizzazione.

Stato condiviso

Le app sul lato Blazor server sono attive in memoria server e più sessioni di app sono ospitate nello stesso processo. Per ogni sessione dell'app, Blazor avvia un circuito con il proprio contenitore delle iniezioni di dipendenza, pertanto i servizi assegnati sono univoci per la sessione Blazor.

Avviso

Non consigliamo che le app sullo stesso server condividano lo stato utilizzando servizi singleton, a meno che non si presti estrema attenzione, poiché ciò potrebbe introdurre vulnerabilità di sicurezza, come la perdita di informazioni sull'utente tra circuiti.

Puoi utilizzare servizi singleton con stato nelle app Blazor se sono specificamente progettati per questo. Ad esempio, l'uso di una cache di memoria di tipo singleton è accettabile perché una cache di memoria richiede una chiave per accedere a una determinata voce. Supponendo che gli utenti non abbiano il controllo sulle chiavi della cache utilizzate, lo stato archiviato nella cache non si disperde tra i circuiti.

Per indicazioni generali sulla gestione dello stato, vedere ASP.NET Gestione dello stato coreBlazor.

Sicurezza lato server di dati e credenziali sensibili

Negli ambienti di test/gestione temporanea e produzione, il codice lato Blazor server e le API Web devono usare flussi di autenticazione sicuri che evitano di mantenere le credenziali all'interno del codice del progetto o dei file di configurazione. Al di fuori dei test di sviluppo locali, è consigliabile evitare l'uso di variabili di ambiente per archiviare i dati sensibili, perché le variabili di ambiente non sono l'approccio più sicuro. Per i test di sviluppo locali, lo strumento Secret Manager è consigliato per proteggere i dati sensibili. Per ulteriori informazioni, vedi le seguenti risorse:

Per lo sviluppo e il test locali sul lato client e sul lato server, usare lo strumento Secret Manager per proteggere le credenziali sensibili.

Modello di progetto

Creare una nuova applicazione lato server Blazor seguendo la guida in Strumenti per ASP.NET Core Blazor.

Dopo aver scelto il modello di app sul lato server e aver configurato il progetto, selezionare l'autenticazione dell'app in Tipo di autenticazione:

  • Nessuno (impostazione predefinita): nessuna autenticazione.
  • Account singoli: gli account utente vengono archiviati all'interno dell'app usando ASP.NET Core Identity.
  • Nessuno (impostazione predefinita): nessuna autenticazione.
  • Account singoli: gli account utente vengono archiviati all'interno dell'app usando ASP.NET Core Identity.
  • Microsoft Identity Platform: per altre informazioni, vedere autenticazione e autorizzazione di base ASP.NETBlazor.
  • Windows: usare l'autenticazione di Windows.

Blazor Identity UI (conti individuali)

Blazor supporta la generazione di un'interfaccia utente completa Blazorbasata su Identity quando si sceglie l'opzione di autenticazione per singoli account.

Il modello Blazor Web App genera automaticamente il codice Identity per un database di SQL Server. La versione della riga di comando usa SQLite e include un database SQLite per Identity.

Il modello:

  • Supporta scenari di rendering interattivo lato server (SSR interattivo) e di rendering interattivo lato client (CSR) con utenti autenticati.
  • Aggiunge IdentityRazor componenti e logica correlata per le attività di autenticazione di routine, ad esempio l'accesso e l'uscita degli utenti. I Identity componenti supportano anche funzionalità avanzate Identity , ad esempio la conferma dell'account e il ripristino delle password e l'autenticazione a più fattori usando un'app di terze parti. Si noti che i componenti stessi non supportano l'interattività Identity .
  • Aggiunge i pacchetti e le dipendenze correlati a Identity.
  • Fa riferimento ai pacchetti Identity in _Imports.razor.
  • Crea una classe utente Identity personalizzata (ApplicationUser).
  • Crea e registra un EF Core contesto di database (ApplicationDbContext).
  • Configura il routing per gli endpoint predefiniti Identity .
  • Include la convalida Identity e la logica aziendale.

Per esaminare i componenti del Blazor framework, accedervi nelle cartelle Identity e Pages della cartella Shared nel modello di progetto Account (origine di riferimento).

Quando si scelgono le modalità di rendering Interattive WebAssembly o Interactive Auto, il server gestisce tutte le richieste di autenticazione e autorizzazione e i Identity componenti vengono visualizzati in modo statico sul server nel Blazor Web App progetto principale.

Il framework fornisce un oggetto personalizzato AuthenticationStateProvider nei progetti server e client (.Client) per il flusso dello stato di autenticazione dell'utente nel browser. Il progetto server chiama AddAuthenticationStateSerialization, mentre il progetto client chiama AddAuthenticationStateDeserialization. L'autenticazione nel server anziché nel client consente all'app di accedere allo stato di autenticazione durante la pre-esecuzione e prima dell'inizializzazione del runtime WebAssembly .NET. Le implementazioni personalizzate AuthenticationStateProvider usano il servizio Stato componente persistente (PersistentComponentState) per serializzare lo stato di autenticazione nei commenti HTML e quindi leggerlo di nuovo da WebAssembly per creare una nuova AuthenticationState istanza. Per altre informazioni, vedere la sezione Gestire lo stato di autenticazione in Blazor Web Apps .

Solo per le soluzioni Interactive Server, IdentityRevalidatingAuthenticationStateProvider (origine di riferimento) è un AuthenticationStateProvider lato server che riconvalida il token di sicurezza per l'utente connesso ogni 30 minuti in cui è collegato un circuito interattivo.

Quando si scelgono le modalità di rendering Interattive WebAssembly o Interactive Auto, il server gestisce tutte le richieste di autenticazione e autorizzazione e i Identity componenti vengono visualizzati in modo statico sul server nel Blazor Web App progetto principale. Il modello di progetto include una PersistentAuthenticationStateProvider classe (origine di riferimento) nel .Client progetto per sincronizzare lo stato di autenticazione dell'utente tra il server e il browser. La classe è un'implementazione personalizzata di AuthenticationStateProvider. Il provider usa il servizio Stato componente persistente (PersistentComponentState) per prerendere lo stato di autenticazione e salvarlo in modo permanente nella pagina.

Nel progetto principale di un , il provider dello stato di autenticazione è denominato (origine di riferimento) (solo soluzioni di interattività server) oppure (origine di riferimento) (soluzioni di interattività WebAssembly o automatica).

Blazor Identity dipende dalle DbContext istanze non create da una factory, che è intenzionale perché DbContext è sufficiente per il rendering statico dei componenti del modello di Identity progetto senza supportare l'interattività.

Per una descrizione del modo in cui le modalità di rendering interattive globali vengono applicate ai componenti diversi da , applicando SSR statico contemporaneamente per i componenti, vedere modalità di rendering di ASP.NET Core.

Per altre informazioni sulla persistenza dello stato prerenderato, vedere Prerender ASP.NET Componenti principaliRazor.

Nota

I collegamenti della documentazione all'origine di riferimento .NET in genere caricano il ramo predefinito del repository, che rappresenta lo sviluppo corrente per la prossima versione di .NET. Per selezionare un tag per una versione specifica, usare l'elenco a discesa Cambia rami o tag . Per altre informazioni, vedere Come selezionare un tag di versione del codice sorgente di ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Gestire lo stato di autenticazione in Blazor Web Apps

Questa sezione si applica agli Blazor Web Appche adottano:

  • Conti individuali
  • Rendering lato client (CSR, interattività basata su WebAssembly).

Un provider di stato di autenticazione lato client viene usato solo all'interno di Blazor e non è integrato con il sistema di autenticazione di ASP.NET Core. Durante la pre-esecuzione, Blazor rispetta i metadati definiti nella pagina e usa il sistema di autenticazione ASP.NET Core per determinare se l'utente è autenticato. Quando un utente passa da una pagina a un'altra, viene usato un provider di autenticazione lato client. Quando l'utente aggiorna la pagina (ricaricamento a pagina intera), il provider di stato di autenticazione lato client non è coinvolto nella decisione di autenticazione sul server. Poiché lo stato dell'utente non è persistente dal server, qualsiasi stato di autenticazione gestito sul lato client viene perso.

Per risolvere questo problema, l'approccio migliore consiste nell'eseguire l'autenticazione all'interno del sistema di autenticazione principale ASP.NET. Il provider di stato di autenticazione lato client si occupa solo di riflettere lo stato di autenticazione dell'utente. Gli esempi di come eseguire questa operazione con i provider di stato di autenticazione sono illustrati dal Blazor Web App modello di progetto e descritti di seguito.

Nel file del progetto server , chiamare , che serializza restituito dal lato server usando il servizio di Stato Componente Persistente ():

builder.Services.AddRazorComponents()
    .AddInteractiveWebAssemblyComponents()
    .AddAuthenticationStateSerialization();

L'API serializza solo le dichiarazioni di nome e di ruolo del lato server per l'accesso nel browser. Per includere tutte le attestazioni, impostare SerializeAllClaims su true nella chiamata server a AddAuthenticationStateSerialization:

builder.Services.AddRazorComponents()
    .AddInteractiveWebAssemblyComponents()
    .AddAuthenticationStateSerialization(
        options => options.SerializeAllClaims = true);

Nel file del progetto client (.Client) Program, chiamare AddAuthenticationStateDeserialization, che aggiunge un AuthenticationStateProvider dove AuthenticationState viene deserializzato dal server tramite AuthenticationStateData e il servizio Stato Componente Persistente (PersistentComponentState). Deve essere presente una chiamata corrispondente a AddAuthenticationStateSerialization nel progetto server.

builder.Services.AddAuthorizationCore();
builder.Services.AddCascadingAuthenticationState();
builder.Services.AddAuthenticationStateDeserialization();
  • PersistingRevalidatingAuthenticationStateProvider (origine di riferimento): per Blazor Web Apps che adottano il rendering interattivo lato server (SSR interattivo) e il rendering lato client (CSR). Si tratta di un componente lato server AuthenticationStateProvider che riconvalida il contrassegno di sicurezza per l'utente connesso ogni 30 minuti in cui un circuito interattivo è connesso. Usa anche il servizio Stato Componente Persistente per trasmettere lo stato di autenticazione al client, che rimane invariato per l'intera durata della Richiesta di Firma del Certificato.

  • PersistingServerAuthenticationStateProvider (origine di riferimento): per Blazor Web Apps che adottano solo CSR. Si tratta di un lato AuthenticationStateProvider server che usa il servizio Stato componente persistente per trasferire lo stato di autenticazione al client, che viene quindi risolto per la durata della richiesta di firma del certificato.

  • PersistentAuthenticationStateProvider (origine di riferimento): per Blazor Web App che adottano la CSR. Si tratta di un client-side AuthenticationStateProvider che determina lo stato di autenticazione dell'utente cercando dati persistenti nella pagina quando è stata eseguita la renderizzazione sul server. Questo stato di autenticazione è fisso per la durata della richiesta di firma del certificato (CSR). Se l'utente deve accedere o disconnettersi, è necessario ricaricare a pagina intera. Questo fornisce solo un nome utente e un messaggio di posta elettronica a scopo di visualizzazione. Non include i token che eseguono l'autenticazione al server quando effettuano richieste successive, che vengono gestite separatamente usando un cookie incluso su HttpClient per le richieste al server.

Nota

I collegamenti della documentazione all'origine di riferimento .NET in genere caricano il ramo predefinito del repository, che rappresenta lo sviluppo corrente per la prossima versione di .NET. Per selezionare un tag per una versione specifica, usare l'elenco a discesa Cambia rami o tag . Per altre informazioni, vedere Come selezionare un tag di versione del codice sorgente di ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Completare lo scaffolding di Identity

Per ulteriori informazioni sullo scaffolding Identity in un'applicazione server-side Blazor, vedere Scaffold Identity nei progetti ASP.NET Core.

Eseguire lo scaffolding Identity all'interno di un'app server-side Blazor.

Attestazioni e token aggiuntivi da provider esterni

Per archiviare attestazioni aggiuntive da provider esterni, vedere Rendere persistenti attestazioni e token aggiuntivi da provider esterni in ASP.NET Core.

Servizio app di Azure in Linux con Identity Server

Specificare esplicitamente l'autorità emittente durante la distribuzione su Azure App Service per Linux con Identity Server. Per ulteriori informazioni, vedere Usa Identity per proteggere un back-end dell'API Web per le SPA (Single-Page Applications).

Iniettare AuthenticationStateProvider per i servizi con ambito ristretto a un componente

Non tentare di risolvere AuthenticationStateProvider all'interno di un ambito personalizzato perché comporta la creazione di una nuova istanza di AuthenticationStateProvider che non è inizializzata correttamente.

Per accedere alla AuthenticationStateProvider all'interno di un servizio con ambito a un componente, inserire il AuthenticationStateProvider nel componente e passarlo al servizio come parametro. Questo approccio garantisce che venga utilizzata l'istanza corretta e inizializzata di AuthenticationStateProvider per ogni istanza dell'applicazione utente.

ExampleService.cs:

public class ExampleService
{
    public async Task<string> ExampleMethod(AuthenticationStateProvider authStateProvider)
    {
        var authState = await authStateProvider.GetAuthenticationStateAsync();
        var user = authState.User;

        if (user.Identity is not null && user.Identity.IsAuthenticated)
        {
            return $"{user.Identity.Name} is authenticated.";
        }
        else
        {
            return "The user is NOT authenticated.";
        }
    }
}

Registrare il servizio con ambito definito. In un'app lato Blazor server, i servizi a scopo hanno una durata uguale alla durata del circuito di connessione del client.

Nel file Program:

builder.Services.AddScoped<ExampleService>();

In Startup.ConfigureServices di Startup.cs:

services.AddScoped<ExampleService>();

Nel componente InjectAuthStateProvider seguente:

InjectAuthStateProvider.razor:

@page "/inject-auth-state-provider"
@inherits OwningComponentBase
@inject AuthenticationStateProvider AuthenticationStateProvider

<h1>Inject <code>AuthenticationStateProvider</code> Example</h1>

<p>@message</p>

@code {
    private string? message;
    private ExampleService? ExampleService { get; set; }

    protected override async Task OnInitializedAsync()
    {
        ExampleService = ScopedServices.GetRequiredService<ExampleService>();

        message = await ExampleService.ExampleMethod(AuthenticationStateProvider);
    }
}
@page "/inject-auth-state-provider"
@inject AuthenticationStateProvider AuthenticationStateProvider
@inherits OwningComponentBase

<h1>Inject <code>AuthenticationStateProvider</code> Example</h1>

<p>@message</p>

@code {
    private string? message;
    private ExampleService? ExampleService { get; set; }

    protected override async Task OnInitializedAsync()
    {
        ExampleService = ScopedServices.GetRequiredService<ExampleService>();

        message = await ExampleService.ExampleMethod(AuthenticationStateProvider);
    }
}

Per ulteriori informazioni, consultare le indicazioni su OwningComponentBase in ASP.NET Core Blazor dependency injection.

Visualizzazione di contenuto non autorizzato durante il pre-rendering utilizzando un oggetto personalizzato AuthenticationStateProvider

Per evitare di visualizzare contenuti non autorizzati, ad esempio contenuti in un AuthorizeView componente, durante il pre-rendering con un componente personalizzato AuthenticationStateProvider, adottare uno dei seguenti approcci:

  • Disabilita prerendering: indicando la modalità di rendering con il prerender parametro impostato su false alla componente di livello più alto nella gerarchia dei componenti dell'app, che non costituisce un componente radice.

    Nota

    Rendere interattivo un componente radice, ad esempio il App componente, non è supportato. Di conseguenza, il prerendering non può essere disabilitato direttamente dal App componente.

    Per le app basate sul modello di Blazor Web App progetto, il prerendering viene in genere disabilitato quando il componente Routes viene usato nel componente App (Components/App.razor) :

    <Routes @rendermode="new InteractiveServerRenderMode(prerender: false)" />
    

    Disabilita anche la prerendering per il componente HeadOutlet:

    <HeadOutlet @rendermode="new InteractiveServerRenderMode(prerender: false)" />
    

    È anche possibile controllare in modo selettivo la modalità di rendering applicata all'istanza del Routes componente. Ad esempio, vedere le modalità di rendering di ASP.NET Core.

  • Disabilita prerendering: aprire il _Host.cshtml file e modificare l'attributo dell'helper render-modetag del componente in Server:

    <component type="typeof(App)" render-mode="Server" />
    
  • Autenticare l'utente sul server prima dell'avvio dell'app: per adottare questo approccio, l'app deve rispondere alla richiesta iniziale di un utente con la pagina di accesso o la vista basata su Identity e impedire qualsiasi richiesta agli endpoint Blazor finché non sono autenticati. Per altre informazioni, vedere Creare un'app ASP.NET Core con i dati utente protetti dall'autorizzazione. Dopo l'autenticazione, il contenuto non autorizzato nei componenti prerenderati Razor viene visualizzato solo quando l'utente non è realmente autorizzato a visualizzare il contenuto.

Gestione dello stato utente

Nonostante la parola "state" nel nome, AuthenticationStateProvider non è per memorizzare lo stato generale dell'utente. AuthenticationStateProvider indica solo lo stato di autenticazione dell'utente all'app, se l'utente ha eseguito l'accesso all'app e con quale identità ha eseguito l'accesso.

L'autenticazione utilizza la stessa autenticazione ASP.NET Core Identity di app Pages e app MVC. Lo stato utente archiviato per ASP.NET Core Identity fluisce verso Blazor senza dover scrivere altro codice per l'app. Seguire le indicazioni riportate negli articoli e nei tutorial di ASP.NET Core Identity affinché le funzionalità Identity abbiano effetto nelle parti Blazor dell'app.

Per indicazioni sulla gestione generale dello stato all'esterno di ASP.NET CoreIdentity, vedere ASP.NET Gestione dello stato coreBlazor.

Astrazioni di sicurezza aggiuntive

Due astrazioni aggiuntive partecipano alla gestione dello stato di autenticazione:

Nota

I collegamenti della documentazione all'origine di riferimento .NET in genere caricano il ramo predefinito del repository, che rappresenta lo sviluppo corrente per la prossima versione di .NET. Per selezionare un tag per una versione specifica, usare l'elenco a discesa Cambia rami o tag . Per altre informazioni, vedere Come selezionare un tag di versione del codice sorgente di ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Gestione dello stato di autenticazione al momento della disconnessione

Server-side Blazor mantiene lo stato di autenticazione dell'utente per tutta la durata del circuito, incluse le schede del browser. Per disconnettere in modo proattivo un utente tra le schede del browser quando l'utente si disconnette da una scheda, è necessario implementare un RevalidatingServerAuthenticationStateProvider (sorgente di riferimento) con un breve RevalidationInterval.

Nota

I collegamenti della documentazione all'origine di riferimento .NET in genere caricano il ramo predefinito del repository, che rappresenta lo sviluppo corrente per la prossima versione di .NET. Per selezionare un tag per una versione specifica, usare l'elenco a discesa Cambia rami o tag . Per altre informazioni, vedere Come selezionare un tag di versione del codice sorgente di ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Durata della validità dell'URL di reindirizzamento temporaneo

Questa sezione si applica a Blazor Web Apps.

Usare l'opzione RazorComponentsServiceOptions.TemporaryRedirectionUrlValidityDuration per ottenere o impostare la durata della validità di ASP.NET Core Data Protection per gli URL di reindirizzamento temporaneo emessi dal Blazor rendering lato server. Questi vengono usati solo temporaneamente, quindi la durata deve essere sufficiente per consentire a un client di ricevere l'URL e iniziare a spostarsi. Tuttavia, dovrebbe anche essere abbastanza lungo per consentire lo sfasamento dell'orologio tra i server. Il valore predefinito è cinque minuti.

Nell'esempio seguente il valore viene esteso a sette minuti:

builder.Services.AddRazorComponents(options => 
    options.TemporaryRedirectionUrlValidityDuration = 
        TimeSpan.FromMinutes(7));

Autenticazione client-side Blazor

Nelle app sul lato client, i controlli di autenticazione lato Blazor client possono essere ignorati perché tutto il codice lato client può essere modificato dagli utenti. Lo stesso vale per tutte le tecnologie delle app lato client, inclusi framework SPA JavaScript e app native per qualsiasi sistema operativo.

Aggiungere quanto segue:

Per gestire l'autenticazione, usare il servizio predefinito o personalizzato AuthenticationStateProvider .

Per altre informazioni sull'autenticazione lato client, vedere Secure ASP.NET Core Blazor WebAssembly.

Proteggere i dati in Blazor Web Apps con rendering automatico interattivo

Quando un Blazor Web App oggetto adotta il rendering lato server (SSR) e il rendering lato client (CSR) per i componenti o un'intera app che specifica la modalità di rendering automatica interattiva, l'autorizzazione per accedere ai componenti e ai dati viene applicata in due posizioni. Il componente limita l'accesso a se stesso (e a tutti i dati ottenuti) quando viene eseguito il rendering nel server in virtù di un attributo di autorizzazione nel file di definizione del componente (@attribute [Authorize]). Quando viene eseguito il rendering del componente nel client, l'accesso ai dati viene limitato tramite gli endpoint dell'API Web del server chiamati dal client. Prestare attenzione quando si protegge l'accesso ai dati in entrambe le posizioni per impedire l'accesso improprio ai dati.

Si consideri lo scenario seguente in cui i dati meteo sicuri vengono visualizzati da un componente. L'esempio seguente può essere esaminato e illustrato in un'app di esempio in esecuzione con gli BlazorWebAppEntra/BlazorWebAppEntraBff esempi (.NET 9 o versione successiva) o l'esempio BlazorWebAppOidc (.NET 8 o versione successiva) nel Blazor repository GitHub degli esempi () (dotnet/blazor-samplescome scaricare).

Il progetto client gestisce una classe WeatherForecast per contenere i dati meteo:

public sealed class WeatherForecast(DateOnly date, int temperatureC, string summary)
{
    public DateOnly Date { get; set; } = date;
    public int TemperatureC { get; set; } = temperatureC;
    public string? Summary { get; set; } = summary;
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}

L'interfaccia IWeatherForecaster del progetto client definisce un metodo GetWeatherForecastAsync per ottenere i dati meteo:

public interface IWeatherForecaster
{
    Task<IEnumerable<WeatherForecast>> GetWeatherForecastAsync();
}

Il servizio del progetto cliente ClientWeatherForecaster implementa IWeatherForecaster. Il metodo GetWeatherForecastAsync chiama un'API Web nel progetto server nell'endpoint /weather-forecast per i dati meteo:

internal sealed class ClientWeatherForecaster(HttpClient httpClient) 
    : IWeatherForecaster
{
    public async Task<IEnumerable<WeatherForecast>> GetWeatherForecastAsync() =>
        await httpClient.GetFromJsonAsync<WeatherForecast[]>("/weather-forecast") ??
            throw new IOException("No weather forecast!");
}

Il progetto client gestisce un componente denominato Weather che:

@page "/weather"
@using Microsoft.AspNetCore.Authorization
@using BlazorWebAppEntra.Client.Weather
@attribute [Authorize]
@inject IWeatherForecaster WeatherForecaster

<PageTitle>Weather</PageTitle>

<h1>Weather</h1>

<p>This component demonstrates showing data.</p>

@if (Forecasts == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Date</th>
                <th aria-label="Temperature in Celsius">Temp. (C)</th>
                <th aria-label="Temperature in Fahrenheit">Temp. (F)</th>
                <th>Summary</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var forecast in Forecasts)
            {
                <tr>
                    <td>@forecast.Date.ToShortDateString()</td>
                    <td>@forecast.TemperatureC</td>
                    <td>@forecast.TemperatureF</td>
                    <td>@forecast.Summary</td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
    [SupplyParameterFromPersistentComponentState]
    public IEnumerable<WeatherForecast>? Forecasts { get; set; }

    protected override async Task OnInitializedAsync()
    {
        Forecasts ??= await WeatherForecaster.GetWeatherForecastAsync();
    }
}
@page "/weather"
@using Microsoft.AspNetCore.Authorization
@using BlazorWebAppEntra.Client.Weather
@attribute [Authorize]
@implements IDisposable
@inject PersistentComponentState ApplicationState
@inject IWeatherForecaster WeatherForecaster

<PageTitle>Weather</PageTitle>

<h1>Weather</h1>

<p>This component demonstrates showing data.</p>

@if (forecasts == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Date</th>
                <th aria-label="Temperature in Celsius">Temp. (C)</th>
                <th aria-label="Temperature in Fahrenheit">Temp. (F)</th>
                <th>Summary</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var forecast in forecasts)
            {
                <tr>
                    <td>@forecast.Date.ToShortDateString()</td>
                    <td>@forecast.TemperatureC</td>
                    <td>@forecast.TemperatureF</td>
                    <td>@forecast.Summary</td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
    private IEnumerable<WeatherForecast>? forecasts;
    private PersistingComponentStateSubscription persistingSubscription;

    protected override async Task OnInitializedAsync()
    {
        if (!ApplicationState.TryTakeFromJson<IEnumerable<WeatherForecast>>(
            nameof(forecasts), out var restoredData))
        {
            forecasts = await WeatherForecaster.GetWeatherForecastAsync();
        }
        else
        {
            forecasts = restoredData!;
        }

        // Call at the end to avoid a potential race condition at app shutdown
        persistingSubscription = ApplicationState.RegisterOnPersisting(PersistData);
    }

    private Task PersistData()
    {
        ApplicationState.PersistAsJson(nameof(forecasts), forecasts);

        return Task.CompletedTask;
    }

    void IDisposable.Dispose() => persistingSubscription.Dispose();
}

Il progetto server implementa IWeatherForecaster come ServerWeatherForecaster, che genera e restituisce dati meteo fittizi tramite il relativo metodo GetWeatherForecastAsync:

internal sealed class ServerWeatherForecaster() : IWeatherForecaster
{
    public readonly string[] summaries =
    [
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", 
        "Sweltering", "Scorching"
    ];

    public async Task<IEnumerable<WeatherForecast>> GetWeatherForecastAsync()
    {
        // Simulate asynchronous loading to demonstrate streaming rendering
        await Task.Delay(500);

        return Enumerable.Range(1, 5).Select(index =>
            new WeatherForecast
            (
                DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
                Random.Shared.Next(-20, 55),
                summaries[Random.Shared.Next(summaries.Length)]
            ))
        .ToArray();
    }
}

In alternativa, ServerWeatherForecaster può chiamare un'API Web esterna usando un approccio denominato Client HTTP e gestore di token, come illustrato nell'esempio seguente:

internal sealed class ServerWeatherForecaster(IHttpClientFactory clientFactory) : IWeatherForecaster
{
    public async Task<IEnumerable<WeatherForecast>> GetWeatherForecastAsync()
    {
        var request = new HttpRequestMessage(HttpMethod.Get, "/weather-forecast");
        var client = clientFactory.CreateClient("ExternalApi");

        var response = await client.SendAsync(request);

        response.EnsureSuccessStatusCode();

        return await response.Content.ReadFromJsonAsync<WeatherForecast[]>() ??
            throw new IOException("No weather forecast!");
    }
}

Se l'app usa pacchetti Web Microsoft Identity Platform/ perMicrosoft IdentityEntra ID (vedere Chiamare un'API Web da un'app ASP.NET CoreBlazor), potrebbe ServerWeatherForecaster essere simile alla classe seguente per effettuare chiamate API Web esterne:

internal sealed class ServerWeatherForecaster(IDownstreamApi downstreamApi) : IWeatherForecaster
{
    public async Task<IEnumerable<WeatherForecast>> GetWeatherForecastAsync()
    {
        var response = await downstreamApi.CallApiForUserAsync("DownstreamApi",
            options =>
            {
                options.RelativePath = "/weather-forecast";
            });

        return await response.Content.ReadFromJsonAsync<WeatherForecast[]>() ??
            throw new IOException("No weather forecast!");
    }
}

Il progetto server gestisce un endpoint API Web sicuro per le chiamate ai dati meteo del client:

app.MapGet("/weather-forecast", (
    [FromServices] IWeatherForecaster WeatherForecaster) =>
{
    return WeatherForecaster.GetWeatherForecastAsync();
}).RequireAuthorization();

Usando l'approccio precedente, sono disponibili due sistemi per fornire dati meteo sicuri all'utente:

  • Quando il rendering del componente Weather viene eseguito sul server, il metodo del servizio ServerWeatherForecaster viene usato direttamente per ottenere i dati meteo. La sicurezza dei dati viene applicata dall'attributo del [Authorize]componente. In sintesi, la sicurezza dei dati meteo viene applicata dal componente.
  • Quando viene eseguito il rendering del Weather componente nel client, il ClientWeatherForecaster servizio viene utilizzato per eseguire una chiamata API web all'endpoint sicuro /weather-forecast che applica il RequireAuthorization metodo di estensione. Se l'utente dispone dell'autorità per accedere ai dati meteo, l'endpoint usa il servizio ServerWeatherForecaster per chiamare GetWeatherForecastAsync. I dati vengono restituiti al client. In sintesi, la sicurezza dei dati meteo viene applicata dall'endpoint API Web dell'app server.

L'approccio precedente funziona correttamente quando i requisiti di sicurezza dell'API Web soddisfano i requisiti di sicurezza del componente. Ad esempio, gli stessi criteri di autorizzazione possono essere applicati sia all'endpoint dell'API Web che al componente.

Gli scenari complessi richiedono una pianificazione e un'implementazione aggiuntive. Ad esempio, un'API Web server con più chiamanti con autorizzazioni di accesso diverse richiede criteri di autorizzazione più sofisticati, uno o più criteri aggiuntivi o endpoint aggiuntivi con requisiti di accesso diversi.

Quando si integra la sicurezza nelle app che adottano il rendering automatico interattivo, tenere presente che la sicurezza implementata per gli endpoint API Web del server non protegge l'implementazione del servizio del server usata quando viene eseguito il rendering di un componente nel server e accede ai dati tramite il servizio. Valutare attentamente la differenza tra l'accesso ai dati nel server durante ssrs e l'accesso ai dati in una richiesta api Web client durante la richiesta csr. Applicare in modo strategico la sicurezza per evitare l'accesso improprio ai dati.

Esempi nel Blazor repository GitHub di esempi () (dotnet/blazor-samplescome scaricare) che illustrano l'approccio descritto in questa sezione:

  • BlazorWebAppOidc
  • BlazorWebAppOidcBff
  • BlazorWebAppEntra
  • BlazorWebAppEntraBff

AuthenticationStateProvider servizio

AuthenticationStateProvider è il servizio sottostante usato dal AuthorizeView componente e dai servizi di autenticazione a catena per ottenere lo stato di autenticazione per un utente.

AuthenticationStateProvider è il servizio sottostante utilizzato dal componente AuthorizeView e dal componente CascadingAuthenticationState per ottenere lo stato di autenticazione per un utente.

In genere non si usa AuthenticationStateProvider direttamente. Usa il AuthorizeView componente o i Task<AuthenticationState> approcci descritti più avanti in questo articolo. Lo svantaggio principale dell'uso diretto di AuthenticationStateProvider è che il componente non riceve alcuna notifica automaticamente se i dati relativi allo stato di autenticazione sottostanti cambiano.

Per implementare un oggetto personalizzatoAuthenticationStateProvider, vedere ASP.NET stato di autenticazione coreBlazor, che include indicazioni sull'implementazione delle notifiche di modifica dello stato di autenticazione utente.

Ottenere i dati delle attestazioni di un utente

Il AuthenticationStateProvider servizio può fornire i dati dell'utente ClaimsPrincipal corrente, come illustrato nell'esempio seguente.

ClaimsPrincipalData.razor:

@page "/claims-principal-data"
@using System.Security.Claims
@inject AuthenticationStateProvider AuthenticationStateProvider

<h1>ClaimsPrincipal Data</h1>

<button @onclick="GetClaimsPrincipalData">Get ClaimsPrincipal Data</button>

<p>@authMessage</p>

@if (claims.Any())
{
    <ul>
        @foreach (var claim in claims)
        {
            <li>@claim.Type: @claim.Value</li>
        }
    </ul>
}

<p>@surname</p>

@code {
    private string? authMessage;
    private string? surname;
    private IEnumerable<Claim> claims = Enumerable.Empty<Claim>();

    private async Task GetClaimsPrincipalData()
    {
        var authState = await AuthenticationStateProvider
            .GetAuthenticationStateAsync();
        var user = authState.User;

        if (user.Identity is not null && user.Identity.IsAuthenticated)
        {
            authMessage = $"{user.Identity.Name} is authenticated.";
            claims = user.Claims;
            surname = user.FindFirst(c => c.Type == ClaimTypes.Surname)?.Value;
        }
        else
        {
            authMessage = "The user is NOT authenticated.";
        }
    }
}

Nell'esempio precedente:

  • ClaimsPrincipal.Claims restituisce le attestazioni dell'utente (claims) per la visualizzazione nell'interfaccia utente.
  • La riga che ottiene il cognome dell'utente (surname) chiama ClaimsPrincipal.FindAll con un predicato per filtrare le dichiarazioni dell'utente.
@page "/claims-principal-data"
@using System.Security.Claims
@inject AuthenticationStateProvider AuthenticationStateProvider

<h1>ClaimsPrincipal Data</h1>

<button @onclick="GetClaimsPrincipalData">Get ClaimsPrincipal Data</button>

<p>@authMessage</p>

@if (claims.Any())
{
    <ul>
        @foreach (var claim in claims)
        {
            <li>@claim.Type: @claim.Value</li>
        }
    </ul>
}

<p>@surname</p>

@code {
    private string? authMessage;
    private string? surname;
    private IEnumerable<Claim> claims = Enumerable.Empty<Claim>();

    private async Task GetClaimsPrincipalData()
    {
        var authState = await AuthenticationStateProvider
            .GetAuthenticationStateAsync();
        var user = authState.User;

        if (user.Identity is not null && user.Identity.IsAuthenticated)
        {
            authMessage = $"{user.Identity.Name} is authenticated.";
            claims = user.Claims;
            surname = user.FindFirst(c => c.Type == ClaimTypes.Surname)?.Value;
        }
        else
        {
            authMessage = "The user is NOT authenticated.";
        }
    }
}

Siccome user.Identity.IsAuthenticated è true e dato che l'utente è un ClaimsPrincipal, si possono enumerare le attestazioni e valutare l'appartenenza ai ruoli.

Per altre informazioni sull'inserimento delle dipendenze (DI) e sui servizi, vedere ASP.NET Core Blazor dependency injection e Dependency injection in ASP.NET Core. Per informazioni su come implementare un personalizzato, vedere ASP.NET Core stato di autenticazione.

Esporre lo stato di autenticazione come un parametro a catena

Se i dati dello stato di autenticazione sono necessari per la logica procedurale, ad esempio quando si esegue un'azione attivata dall'utente, ottenere i dati dello stato di autenticazione definendo un parametro a catena di tipo Task<AuthenticationState>, come illustrato nell'esempio seguente.

CascadeAuthState.razor:

@page "/cascade-auth-state"

<h1>Cascade Auth State</h1>

<p>@authMessage</p>

@code {
    private string authMessage = "The user is NOT authenticated.";

    [CascadingParameter]
    private Task<AuthenticationState>? authenticationState { get; set; }

    protected override async Task OnInitializedAsync()
    {
        if (authenticationState is not null)
        {
            var authState = await authenticationState;
            var user = authState?.User;

            if (user?.Identity is not null && user.Identity.IsAuthenticated)
            {
                authMessage = $"{user.Identity.Name} is authenticated.";
            }
        }
    }
}
@page "/cascade-auth-state"

<h1>Cascade Auth State</h1>

<p>@authMessage</p>

@code {
    private string authMessage = "The user is NOT authenticated.";

    [CascadingParameter]
    private Task<AuthenticationState>? authenticationState { get; set; }

    protected override async Task OnInitializedAsync()
    {
        if (authenticationState is not null)
        {
            var authState = await authenticationState;
            var user = authState?.User;

            if (user?.Identity is not null && user.Identity.IsAuthenticated)
            {
                authMessage = $"{user.Identity.Name} is authenticated.";
            }
        }
    }
}

Se user.Identity.IsAuthenticated è true, è possibile enumerare le attestazioni e valutare l'appartenenza ai ruoli.

Configurare il Task<AuthenticationState>parametro a catena usando i servizi per lo stato dell'autenticazione a catena e AuthorizeRouteView.

Quando si crea un'app Blazor da uno dei Blazor modelli di progetto con autenticazione abilitata, l'app include AuthorizeRouteView e la chiamata a AddCascadingAuthenticationState illustrata nell'esempio seguente. Un'app dal lato Blazor client include anche le registrazioni dei servizi necessarie. Altre informazioni sono disponibili nella sezione Personalizzazione dei contenuti non autorizzati con il componente Router.

<Router ...>
    <Found ...>
        <AuthorizeRouteView RouteData="routeData" 
            DefaultLayout="typeof(Layout.MainLayout)" />
        ...
    </Found>
</Router>

Nel file Program registrare i servizi di stato di autenticazione a cascata:

builder.Services.AddCascadingAuthenticationState();

Configurare il Task<AuthenticationState>parametro a catena usando i componenti AuthorizeRouteView e CascadingAuthenticationState.

Quando si crea un'app Blazor da uno dei Blazor modelli di progetto con autenticazione abilitata, l'app include i AuthorizeRouteView componenti e CascadingAuthenticationState illustrati nell'esempio seguente. Un'app dal lato Blazor client include anche le registrazioni dei servizi necessarie. Altre informazioni sono disponibili nella sezione Personalizzazione dei contenuti non autorizzati con il componente Router.

<CascadingAuthenticationState>
    <Router ...>
        <Found ...>
            <AuthorizeRouteView RouteData="routeData" 
                DefaultLayout="typeof(MainLayout)" />
            ...
        </Found>
    </Router>
</CascadingAuthenticationState>

Nota

Con la versione di ASP.NET Core 5.0.1 e per eventuali versioni 5.x aggiuntive, il componente Router include il parametro PreferExactMatches impostato su @true. Per altre informazioni, vedere Eseguire la migrazione da ASP.NET Core 3.1 a 5.0.

In un'app client-side, aggiungi i servizi di autorizzazione al file Blazor:

builder.Services.AddAuthorizationCore();

In un'app client-side Blazor aggiungi opzioni e servizi di autorizzazione al file Program.

builder.Services.AddOptions();
builder.Services.AddAuthorizationCore();

In un'app sul lato Blazor server i servizi per le opzioni e l'autorizzazione sono già presenti, quindi non sono necessari altri passaggi.

Autorizzazione

Dopo l'autenticazione di un utente, le regole di autorizzazione vengono applicate per controllare le operazioni che l'utente può eseguire.

L'accesso viene in genere concesso o negato in base alle condizioni seguenti:

  • L'utente è autenticato (ha eseguito l'accesso).
  • Un utente è in un ruolo.
  • Un utente ha un reclamo.
  • Un criterio è soddisfatto.

Questi concetti sono uguali a quelli validi per un'app ASP.NET Core MVC o Razor Pages. Per altre informazioni sulla sicurezza di ASP.NET Core, vedere gli articoli in ASP.NET Core Security e Identity.

Componente AuthorizeView

Il componente AuthorizeView visualizza in modo selettivo il contenuto dell'interfaccia utente a seconda del fatto che l'utente sia autorizzato. Questo approccio è utile quando è sufficiente visualizzare i dati per l'utente e non è necessario usare l'identità dell'utente nella logica procedurale.

Il componente espone una context variabile di tipo AuthenticationState (@context nella Razor sintassi), che è possibile usare per accedere alle informazioni sull'utente connesso:

<AuthorizeView>
    <p>Hello, @context.User.Identity?.Name!</p>
</AuthorizeView>

È anche possibile fornire contenuto diverso per la visualizzazione se l'utente non è autorizzato con una combinazione dei Authorized parametri e NotAuthorized :

<AuthorizeView>
    <Authorized>
        <p>Hello, @context.User.Identity?.Name!</p>
        <p><button @onclick="HandleClick">Authorized Only Button</button></p>
    </Authorized>
    <NotAuthorized>
        <p>You're not authorized.</p>
    </NotAuthorized>
</AuthorizeView>

@code {
    private void HandleClick() { ... }
}

Anche se il AuthorizeView componente controlla la visibilità degli elementi in base allo stato di autorizzazione dell'utente, non impone la sicurezza sul gestore eventi stesso. Nell'esempio precedente il HandleClick metodo è associato solo a un pulsante visibile agli utenti autorizzati, ma nulla impedisce di richiamare questo metodo da altre posizioni. Per garantire la sicurezza a livello di metodo, implementare logica di autorizzazione aggiuntiva all'interno del gestore stesso o nell'API pertinente.

Razor i componenti di Blazor Web Apps non visualizzano mai il contenuto di <NotAuthorized> quando l'autorizzazione fallisce sul lato server durante il rendering statico lato server (SSR statico). La pipeline di ASP.NET Core lato server elabora l'autorizzazione sul server. Usare tecniche lato server per gestire le richieste non autorizzate. Per ulteriori informazioni, vedere Modalità di rendering di ASP.NET CoreBlazor.

Avviso

Il markup e i metodi lato client associati a un AuthorizeView sono protetti solo dalla visualizzazione e dall'esecuzione nell'interfaccia utente resa nelle applicazioni lato client Blazor. Per proteggere il contenuto autorizzato e i metodi sicuri sul lato Blazorclient, il contenuto viene in genere fornito da una chiamata API Web sicura e autorizzata a un'API server e mai archiviata nell'app. Per altre informazioni, vedere Chiamare un'API Web da un'app ASP.NET Core Blazor e scenari aggiuntivi di sicurezza di ASP.NET CoreBlazor WebAssembly.

Il contenuto di Authorized e NotAuthorized può includere elementi arbitrari, ad esempio altri componenti interattivi.

Le condizioni di autorizzazione, ad esempio ruoli o criteri che controllano le opzioni o l'accesso dell'interfaccia utente, sono illustrate nella sezione Autorizzazione .

Se le condizioni di autorizzazione non vengono specificate, AuthorizeView usa un criterio predefinito:

  • Gli utenti autenticati (connessi) sono autorizzati.
  • Gli utenti non autenticati (non collegati) non sono autorizzati.

Il componente AuthorizeView può essere utilizzato all'interno del componente NavMenu (Shared/NavMenu.razor) per visualizzare un componente NavLink (NavLink), ma si noti che questo approccio rimuove solo l'elemento di elenco dall'output renderizzato. Non impedisce all'utente di passare al componente. Implementare l'autorizzazione separatamente nel componente di destinazione.

Autorizzazione basata sui ruoli e basata sui criteri

Il AuthorizeView componente supporta l'autorizzazione basata su ruoli o basata su criteri .

Per l'autorizzazione basata sui ruoli, usare il Roles parametro . Nell'esempio seguente, l'utente deve avere un'attestazione del ruolo per il ruolo o :

<AuthorizeView Roles="Admin, Superuser">
    <p>You have an 'Admin' or 'Superuser' role claim.</p>
</AuthorizeView>

Per richiedere che un utente disponga di attestazioni di ruolo sia Admin che Superuser, annidare i componenti AuthorizeView.

<AuthorizeView Roles="Admin">
    <p>User: @context.User</p>
    <p>You have the 'Admin' role claim.</p>
    <AuthorizeView Roles="Superuser" Context="innerContext">
        <p>User: @innerContext.User</p>
        <p>You have both 'Admin' and 'Superuser' role claims.</p>
    </AuthorizeView>
</AuthorizeView>

Il codice precedente stabilisce un oggetto Context per il componente interno AuthorizeView per evitare un AuthenticationState conflitto di contesto. Il contesto AuthenticationState viene acceduto all'esterno AuthorizeView con l'approccio standard per accedere al contesto (@context.User). Il contesto viene acceduto nel AuthorizeView interno con il contesto denominato innerContext (@innerContext.User).

Per altre informazioni, incluse le linee guida sulla configurazione, vedere Autorizzazione basata su ruoli in ASP.NET Core.

Per l'autorizzazione basata su criteri, usare il Policy parametro con un singolo nome di criteri:

<AuthorizeView Policy="Over21">
    <p>You satisfy the 'Over21' policy.</p>
</AuthorizeView>

Per gestire il caso in cui l'utente deve soddisfare uno dei diversi criteri, creare un criterio che conferma che l'utente soddisfi altri criteri.

Per gestire il caso in cui l'utente deve soddisfare contemporaneamente diversi criteri, adottare uno degli approcci seguenti:

  • Creare un criterio per AuthorizeView che conferma che l'utente soddisfi diversi altri criteri.

  • Annida le politiche in più componenti AuthorizeView

    <AuthorizeView Policy="Over21">
        <AuthorizeView Policy="LivesInCalifornia">
            <p>You satisfy the 'Over21' and 'LivesInCalifornia' policies.</p>
        </AuthorizeView>
    </AuthorizeView>
    

L'autorizzazione basata sulle attestazioni è un caso speciale di autorizzazione basata su criteri. Ad esempio, è possibile definire un criterio che richiede che gli utenti abbiano una determinata attestazione. Per altre informazioni, vedere Autorizzazione basata su criteri in ASP.NET Core.

Se Roles e Policy sono impostati, l'autorizzazione ha esito positivo solo quando entrambe le condizioni vengono soddisfatte. Ovvero, l'utente deve appartenere ad almeno uno dei ruoli specificati e soddisfare i requisiti definiti dai criteri.

Se non viene specificato né RolesPolicy , AuthorizeView usa i criteri predefiniti:

  • Gli utenti autenticati (connessi) sono autorizzati.
  • Gli utenti non autenticati (non collegati) non sono autorizzati.

Poiché i confronti tra stringhe .NET sono sensibili alle maiuscole, anche i nomi dei ruoli e dei criteri corrispondenti sono sensibili alle maiuscole. Ad esempio, Admin (maiuscolo A) non viene considerato come lo stesso ruolo di admin (minuscolo a).

Il caso Pascal viene in genere usato per i nomi dei ruoli e dei criteri ,ad esempio BillingAdministrator, ma l'uso del caso Pascal non è un requisito rigoroso. Sono consentiti diversi schemi di maiuscole e minuscole, come la notazione camel case, la notazione kebab case e la notazione snake case. L'uso di spazi nei nomi di ruoli e criteri è insolito ma consentito dal framework. Ad esempio, billing administrator è un formato insolito di ruoli o nomi di criteri nelle app .NET, ma si tratta di un ruolo o un nome di criteri valido.

Contenuto visualizzato durante l'autenticazione asincrona

Blazor consente di determinare lo stato di autenticazione in modo asincrono. Lo scenario principale per questo approccio riguarda le app lato client Blazor che effettuano una richiesta a un endpoint esterno per l'autenticazione.

Mentre l'autenticazione è in corso, AuthorizeView non visualizza alcun contenuto. Per visualizzare il contenuto durante l'autenticazione, assegnare il contenuto al Authorizing parametro :

<AuthorizeView>
    <Authorized>
        <p>Hello, @context.User.Identity?.Name!</p>
    </Authorized>
    <Authorizing>
        <p>You can only see this content while authentication is in progress.</p>
    </Authorizing>
</AuthorizeView>

Questo approccio non è in genere applicabile alle app Blazor lato server. Le app lato server Blazor conoscono lo stato di autenticazione non appena viene stabilito. Authorizing il contenuto può essere fornito nel componente di AuthorizeView un'app, ma il contenuto non viene mai visualizzato.

[Authorize] attributo

L'attributo[Authorize] è disponibile nei Razor componenti:

@page "/"
@attribute [Authorize]

You can only see this if you're signed in.

Importante

Usare [Authorize] solo sui componenti @page raggiunti tramite il router Blazor. L'autorizzazione viene eseguita solo come aspetto del routing e non per i componenti figlio di cui viene eseguito il rendering all'interno di una pagina. Per autorizzare la visualizzazione di parti specifiche all'interno di una pagina, usare invece AuthorizeView.

L'attributo supporta anche l'autorizzazione [Authorize] basata su ruoli o basata su criteri. Per l'autorizzazione basata sui ruoli, usare il parametro Roles:

@page "/"
@attribute [Authorize(Roles = "Admin, Superuser")]

<p>You can only see this if you're in the 'Admin' or 'Superuser' role.</p>

Per l'autorizzazione basata sui criteri, usare il parametro Policy:

@page "/"
@attribute [Authorize(Policy = "Over21")]

<p>You can only see this if you satisfy the 'Over21' policy.</p>

Se non viene specificato né RolesPolicy , [Authorize] usa i criteri predefiniti:

  • Gli utenti autenticati (connessi) sono autorizzati.
  • Gli utenti non autenticati (non collegati) non sono autorizzati.

Quando l'utente non è autorizzato e se l'app non personalizza il contenuto non autorizzato con il Router componente, il framework visualizza automaticamente il messaggio di fallback seguente:

Not authorized.

Autorizzazione delle risorse

Per autorizzare gli utenti alle risorse, passare i dati di route della richiesta al parametro Resource di AuthorizeRouteView.

Nel contenuto Router.Found per un percorso richiesto:

<AuthorizeRouteView Resource="routeData" RouteData="routeData" 
    DefaultLayout="typeof(MainLayout)" />

Per altre informazioni sul modo in cui i dati sullo stato di autorizzazione vengono passati e usati nella logica procedurale, vedere la sezione Esporre lo stato di autenticazione come parametro a catena .

Quando AuthorizeRouteView riceve i dati di route per la risorsa, i criteri di autorizzazione hanno accesso a RouteData.PageType e RouteData.RouteValues che consentono alla logica personalizzata di prendere decisioni per l'autorizzazione.

Nell'esempio seguente viene creato un criterio EditUser in AuthorizationOptions per la configurazione del servizio di autorizzazione dell'app (AddAuthorizationCore) con la logica seguente:

  • Determinare se esiste un valore di route con una chiave di id. Se la chiave esiste, il valore della route viene archiviato in value.
  • In una variabile denominata id, archiviare value come stringa o impostare un valore stringa vuoto (string.Empty).
  • Se id non è una stringa vuota, confermare che il criterio è soddisfatto (restituire true) se il valore della stringa inizia con EMP. In caso contrario, affermare che la politica fallisce (restituire false).

Nel file Program:

  • Aggiungere spazi dei nomi per Microsoft.AspNetCore.Components e System.Linq:

    using Microsoft.AspNetCore.Components;
    using System.Linq;
    
  • Aggiungere il criterio:

    options.AddPolicy("EditUser", policy =>
        policy.RequireAssertion(context =>
        {
            if (context.Resource is RouteData rd)
            {
                var routeValue = rd.RouteValues.TryGetValue("id", out var value);
                var id = Convert.ToString(value, 
                    System.Globalization.CultureInfo.InvariantCulture) ?? string.Empty;
    
                if (!string.IsNullOrEmpty(id))
                {
                    return id.StartsWith("EMP", StringComparison.InvariantCulture);
                }
            }
    
            return false;
        })
    );
    

L'esempio precedente è un criterio di autorizzazione molto semplificato, usato semplicemente per una dimostrazione del concetto con un esempio funzionante. Per altre informazioni sulla creazione e la configurazione dei criteri di autorizzazione, vedere Autorizzazione basata su criteri in ASP.NET Core.

Nel componente EditUser seguente la risorsa in /users/{id}/edit ha un parametro di route per l'identificatore dell'utente ({id}). Il componente usa il criterio di autorizzazione EditUser precedente per determinare se il valore della route per id inizia con EMP. Se inizia id con EMP, il criterio è soddisfatto e l'accesso al componente viene autorizzato. Se id inizia con un valore diverso da EMP o se id è una stringa vuota, il criterio non è soddisfatto e il componente non viene caricato.

EditUser.razor:

@page "/users/{id}/edit"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Policy = "EditUser")]

<h1>Edit User</h1>

<p>The "EditUser" policy is satisfied! <code>Id</code> starts with 'EMP'.</p>

@code {
    [Parameter]
    public string? Id { get; set; }
}
@page "/users/{id}/edit"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Policy = "EditUser")]

<h1>Edit User</h1>

<p>The "EditUser" policy is satisfied! <code>Id</code> starts with 'EMP'.</p>

@code {
    [Parameter]
    public string? Id { get; set; }
}

Personalizzare il contenuto non autorizzato con il Router componente

Il componente Router, insieme al componente AuthorizeRouteView, consente all'app di specificare il contenuto personalizzato se:

  • L'utente non soddisfa una condizione [Authorize] applicata al componente. Viene visualizzato il markup dell'elemento <NotAuthorized>. L'attributo [Authorize] è trattato nella sezione dell'attributo[Authorize].
  • L'autorizzazione asincrona è in corso, il che significa in genere che il processo di autenticazione dell'utente è in corso. Viene visualizzato il markup dell'elemento <Authorizing>.

Importante

Blazor Le funzionalità del router che visualizzano <NotAuthorized> e <NotFound> contenuti non sono operative durante il rendering statico lato server (SSR statico) perché l'elaborazione delle richieste è interamente gestita dalla pipeline middleware di ASP.NET Core e i componenti Razor non vengono renderizzati per richieste non autorizzate o errate. Usare tecniche lato server per gestire richieste non autorizzate e non valide durante SSR statico. Per ulteriori informazioni, vedere Modalità di rendering di ASP.NET CoreBlazor.

<Router ...>
    <Found ...>
        <AuthorizeRouteView ...>
            <NotAuthorized>
                ...
            </NotAuthorized>
            <Authorizing>
                ...
            </Authorizing>
        </AuthorizeRouteView>
    </Found>
</Router>

Il contenuto di Authorized e NotAuthorized può includere elementi arbitrari, ad esempio altri componenti interattivi.

Nota

Il precedente richiede la registrazione dei servizi di stato di autenticazione a catena nel file dell'app Program :

builder.Services.AddCascadingAuthenticationState();
<CascadingAuthenticationState>
    <Router ...>
        <Found ...>
            <AuthorizeRouteView ...>
                <NotAuthorized>
                    ...
                </NotAuthorized>
                <Authorizing>
                    ...
                </Authorizing>
            </AuthorizeRouteView>
        </Found>
    </Router>
</CascadingAuthenticationState>

Il contenuto di NotFound, Authorized e NotAuthorized può includere elementi arbitrari, ad esempio altri componenti interattivi.

Se NotAuthorized il contenuto non è specificato, AuthorizeRouteView usa il messaggio di fallback seguente:

Not authorized.

Un'app creata dal Blazor WebAssembly modello di progetto con l'autenticazione abilitata include un RedirectToLogin componente posizionato nel <NotAuthorized> contenuto del Router componente. Quando un utente non è autenticato (context.User.Identity?.IsAuthenticated != true), il RedirectToLogin componente reindirizza il browser all'endpoint per l'autenticazione authentication/login . L'utente viene restituito all'URL richiesto dopo l'autenticazione con il provider di identità.

Logica procedurale

Se l'app deve controllare le regole di autorizzazione come parte della logica procedurale, usare un parametro a catena di tipo Task<AuthenticationState> per ottenere il ClaimsPrincipal dell'utente. Task< AuthenticationState > può essere combinato con altri servizi, ad esempio IAuthorizationService, per valutare i criteri.

Nell'esempio seguente :

  • user.Identity.IsAuthenticated Esegue il codice per gli utenti autenticati (connessi).
  • Il user.IsInRole("admin") esegue il codice per gli utenti nel ruolo 'Amministratore'.
  • Esegue il codice (await AuthorizationService.AuthorizeAsync(user, "content-editor")).Succeeded per gli utenti che rispettano la policy 'content-editor'.

Le app lato Blazor server includono gli spazi dei nomi appropriati quando vengono create dal modello di progetto. In un'app lato client Blazor, verificare la presenza dei namespace Microsoft.AspNetCore.Authorization e Microsoft.AspNetCore.Components.Authorization nel componente o nel file _Imports.razor dell'app:

@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization

ProceduralLogic.razor:

@page "/procedural-logic"
@inject IAuthorizationService AuthorizationService

<h1>Procedural Logic Example</h1>

<button @onclick="@DoSomething">Do something important</button>

@code {
    [CascadingParameter]
    private Task<AuthenticationState>? authenticationState { get; set; }

    private async Task DoSomething()
    {
        if (authenticationState is not null)
        {
            var authState = await authenticationState;
            var user = authState?.User;

            if (user is not null)
            {
                if (user.Identity is not null && user.Identity.IsAuthenticated)
                {
                    // ...
                }

                if (user.IsInRole("Admin"))
                {
                    // ...
                }

                if ((await AuthorizationService.AuthorizeAsync(user, "content-editor"))
                    .Succeeded)
                {
                    // ...
                }
            }
        }
    }
}
@page "/procedural-logic"
@inject IAuthorizationService AuthorizationService

<h1>Procedural Logic Example</h1>

<button @onclick="@DoSomething">Do something important</button>

@code {
    [CascadingParameter]
    private Task<AuthenticationState>? authenticationState { get; set; }

    private async Task DoSomething()
    {
        if (authenticationState is not null)
        {
            var authState = await authenticationState;
            var user = authState?.User;

            if (user is not null)
            {
                if (user.Identity is not null && user.Identity.IsAuthenticated)
                {
                    // ...
                }

                if (user.IsInRole("Admin"))
                {
                    // ...
                }

                if ((await AuthorizationService.AuthorizeAsync(user, "content-editor"))
                    .Succeeded)
                {
                    // ...
                }
            }
        }
    }
}

Risolvere gli errori

Errori comuni:

  • Per l'autorizzazione è richiesto un parametro a catena di tipo Task<AuthenticationState>. Considerare l'uso di CascadingAuthenticationState per fornire questo.

  • Il valore null è ricevuto per authenticationStateTask

È probabile che il progetto non sia stato creato usando un modello lato server Blazor con l'autenticazione abilitata.

In .NET 7 o versioni precedenti, avvolgi un <CascadingAuthenticationState> attorno a qualche parte dell'albero dell'interfaccia utente, ad esempio attorno al router Blazor.

<CascadingAuthenticationState>
    <Router ...>
        ...
    </Router>
</CascadingAuthenticationState>

In .NET 8 o versione successiva non usare il CascadingAuthenticationState componente :

- <CascadingAuthenticationState>
      <Router ...>
          ...
      </Router>
- </CascadingAuthenticationState>

Invece, aggiungi i servizi di stato dell'autenticazione a cascata alla raccolta di servizi nel file Program.

builder.Services.AddCascadingAuthenticationState();

Il componente CascadingAuthenticationState (.NET 7 o versioni precedenti) o i servizi forniti da AddCascadingAuthenticationState (.NET 8 o versioni successive) forniscono il parametro a cascata Task<AuthenticationState>, che a sua volta riceve dal servizio di iniezione delle dipendenze sottostante AuthenticationStateProvider.

Informazioni personali (PII)

Microsoft usa la definizione del GDPR per i "dati personali" (GDPR 4.1) quando la documentazione illustra le informazioni personali.

PiI fa riferimento a qualsiasi informazione relativa a una persona fisica identificata o identificabile. Una persona fisica identificabile è una persona che può essere identificata, direttamente o indirettamente, con uno dei seguenti elementi:

  • Nome
  • Numero di identificazione
  • Coordinate della posizione
  • Identificatore online
  • Altri fattori specifici
    • Fisico
    • Fisiologico
    • Genetico
    • Mentale (psicologico)
    • economico
    • Culturale
    • Identità sociale

Risorse aggiuntive