Autenticazione e autorizzazione per ASP.NET Core Blazor Hybrid
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 e di ASP.NET Core Identity nelle app Blazor Hybrid.
L'autenticazione nelle app Blazor Hybrid viene gestita dalle librerie della piattaforma nativa perché offrono garanzie di sicurezza avanzata che la sandbox del browser non può offrire. L'autenticazione delle app native usa un meccanismo specifico del sistema operativo o un protocollo federato, ad esempio OpenID Connect (OIDC). Seguire le indicazioni per il identity provider selezionato per l'app e quindi integrarsi identity ulteriormente con Blazor l'uso delle indicazioni riportate in questo articolo.
L'integrazione dell'autenticazione deve raggiungere gli obiettivi seguenti per i componenti e i servizi di Razor:
- Usare le astrazioni nel pacchetto
Microsoft.AspNetCore.Components.Authorization
, ad esempio AuthorizeView. - Reagire alle modifiche nel contesto di autenticazione.
- Credenziali di accesso di cui viene effettuato il identity provisioning dall'app dal provider, ad esempio i token di accesso per eseguire chiamate API autorizzate.
Dopo che l'autenticazione è stata aggiunta a un'app .NET MAUI, WPF o Windows Form e gli utenti possono accedere e disconnettersi correttamente, integrare l'autenticazione con Blazor per rendere l'utente autenticato disponibile per i componenti e i servizi di Razor. Procedi come segue:
Fare riferimento al pacchetto
Microsoft.AspNetCore.Components.Authorization
.Nota
Per indicazioni sull'aggiunta di pacchetti alle app .NET, vedere gli articoli sotto Installare e gestire pacchetti in Flusso di lavoro dell'utilizzo di pacchetti (documentazione di NuGet). Confermare le versioni corrette del pacchetto all'indirizzo NuGet.org.
Implementare una classe AuthenticationStateProvider personalizzata, ovvero l'astrazione usata dai componenti di Razor per accedere alle informazioni sull'utente autenticato e per ricevere gli aggiornamenti quando lo stato dell'autenticazione cambia.
Registrare il provider di stato dell'autenticazione personalizzata nel contenitore di inserimento delle dipendenze.
Le app .NET MAUI usano l'autenticatore Web di Xamarin.Essentials: la classe WebAuthenticator
consente all'app di avviare i flussi di autenticazione basata sul browser che sono in ascolto di un callback a un URL specifico registrato con l'app.
Per altre indicazioni, vedere le risorse seguenti:
Le app WPF usano la piattaforma Microsoft identity per l'integrazione con Microsoft Entra (ME-ID) e AAD B2C. Per indicazioni ed esempi, vedere le risorse seguenti:
- Panoramica di Microsoft Authentication Library (MSAL)
- Aggiungere l'autenticazione all'app Windows (WPF)
- Esercitazione: Far accedere gli utenti e chiamare Microsoft Graph nell'app desktop Windows Presentation Foundation (WPF)
- Avvio rapido: Acquisire un token e chiamare l'API Microsoft Graph da un'applicazione desktop
- Avvio rapido: Configurare l'accesso per un'app desktop tramite Azure Active Directory B2C
- Configurare l'autenticazione in un'app desktop WPF di esempio usando Azure AD B2C
Windows Form le app usano Piattaforma Microsoft identity da integrare con Microsoft Entra (ME-ID) e AAD B2C. Per altre informazioni, vedere Panoramica di Microsoft Authentication Library (MSAL).
Creare una classe AuthenticationStateProvider
personalizzata senza aggiornamenti delle modifiche utente
Se l'app autentica l'utente immediatamente dopo l'avvio dell'app e l'utente autenticato rimane lo stesso per tutta la durata dell'app, le notifiche di modifica utente non sono necessarie e l'app fornisce solo informazioni sull'utente autenticato. In questo scenario l'utente accede all'app quando l'app viene aperta e l'app visualizza nuovamente la schermata di accesso dopo la disconnessione dell'utente. L'elemento ExternalAuthStateProvider
seguente è un'implementazione di esempio di una classe AuthenticationStateProvider personalizzata per questo scenario di autenticazione.
Nota
La classe AuthenticationStateProvider personalizzata seguente non dichiara uno spazio dei nomi per fare in modo che l'esempio di codice sia applicabile a qualsiasi app Blazor Hybrid. È tuttavia consigliabile specificare lo spazio dei nomi dell'app quando si implementa l'esempio in un'app di produzione.
ExternalAuthStateProvider.cs
:
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Authorization;
public class ExternalAuthStateProvider : AuthenticationStateProvider
{
private readonly Task<AuthenticationState> authenticationState;
public ExternalAuthStateProvider(AuthenticatedUser user) =>
authenticationState = Task.FromResult(new AuthenticationState(user.Principal));
public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
authenticationState;
}
public class AuthenticatedUser
{
public ClaimsPrincipal Principal { get; set; } = new();
}
Nei passaggi successivi viene descritto come effettuare le seguenti operazioni:
- Aggiungere gli spazi dei nomi obbligatori.
- Aggiungere i servizi di autorizzazione e le astrazioni di Blazor alla raccolta di servizi.
- Compilare la raccolta di servizi.
- Risolvere il servizio
AuthenticatedUser
per impostare l'entità di sicurezza delle attestazioni dell'utente autenticato. Per informazioni dettagliate, vedere la identity documentazione del provider. - Restituire l'host compilato.
Nel metodo MauiProgram.CreateMauiApp
di MauiProgram.cs
aggiungere gli spazi dei nomi per Microsoft.AspNetCore.Components.Authorization e System.Security.Claims:
using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;
Rimuovere la riga di codice seguente che restituisce un elemento Microsoft.Maui.Hosting.MauiApp compilato:
- return builder.Build();
Sostituire la riga di codice precedente con il codice seguente. Aggiungere il codice OpenID/MSAL per autenticare l'utente. Per informazioni dettagliate, vedere la identity documentazione del provider.
builder.Services.AddAuthorizationCore();
builder.Services.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
builder.Services.AddSingleton<AuthenticatedUser>();
var host = builder.Build();
var authenticatedUser = host.Services.GetRequiredService<AuthenticatedUser>();
/*
Provide OpenID/MSAL code to authenticate the user. See your identity provider's
documentation for details.
The user is represented by a new ClaimsPrincipal based on a new ClaimsIdentity.
*/
var user = new ClaimsPrincipal(new ClaimsIdentity());
authenticatedUser.Principal = user;
return host;
Nei passaggi successivi viene descritto come effettuare le seguenti operazioni:
- Aggiungere gli spazi dei nomi obbligatori.
- Aggiungere i servizi di autorizzazione e le astrazioni di Blazor alla raccolta di servizi.
- Compilare la raccolta di servizi e aggiungere la raccolta di servizi compilata come risorsa al
ResourceDictionary
dell'app. - Risolvere il servizio
AuthenticatedUser
per impostare l'entità di sicurezza delle attestazioni dell'utente autenticato. Per informazioni dettagliate, vedere la identity documentazione del provider. - Restituire l'host compilato.
Nel costruttore di MainWindow
(MainWindow.xaml.cs
) aggiungere gli spazi dei nomi per Microsoft.AspNetCore.Components.Authorization e System.Security.Claims:
using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;
Rimuovere la riga di codice seguente che aggiunge la raccolta di servizi compilata come risorsa al ResourceDictionary
dell'app:
- Resources.Add("services", serviceCollection.BuildServiceProvider());
Sostituire la riga di codice precedente con il codice seguente. Aggiungere il codice OpenID/MSAL per autenticare l'utente. Per informazioni dettagliate, vedere la identity documentazione del provider.
serviceCollection.AddAuthorizationCore();
serviceCollection.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
serviceCollection.AddSingleton<AuthenticatedUser>();
var services = serviceCollection.BuildServiceProvider();
Resources.Add("services", services);
var authenticatedUser = services.GetRequiredService<AuthenticatedUser>();
/*
Provide OpenID/MSAL code to authenticate the user. See your identity provider's
documentation for details.
The user is represented by a new ClaimsPrincipal based on a new ClaimsIdentity.
*/
var user = new ClaimsPrincipal(new ClaimsIdentity());
authenticatedUser.Principal = user;
Nei passaggi successivi viene descritto come effettuare le seguenti operazioni:
- Aggiungere gli spazi dei nomi obbligatori.
- Aggiungere i servizi di autorizzazione e le astrazioni di Blazor alla raccolta di servizi.
- Compilare la raccolta di servizi e aggiungere la raccolta di servizi compilata al provider di servizi dell'app.
- Risolvere il servizio
AuthenticatedUser
per impostare l'entità di sicurezza delle attestazioni dell'utente autenticato. Per informazioni dettagliate, vedere la identity documentazione del provider.
Nel costruttore di Form1
(Form1.cs
) aggiungere gli spazi dei nomi per Microsoft.AspNetCore.Components.Authorization e System.Security.Claims:
using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;
Rimuovere la riga di codice seguente che imposta la raccolta di servizi compilata sul provider di servizi dell'app:
- blazorWebView1.Services = services.BuildServiceProvider();
Sostituire la riga di codice precedente con il codice seguente. Aggiungere il codice OpenID/MSAL per autenticare l'utente. Per informazioni dettagliate, vedere la identity documentazione del provider.
services.AddAuthorizationCore();
services.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
services.AddSingleton<AuthenticatedUser>();
var serviceCollection = services.BuildServiceProvider();
blazorWebView1.Services = serviceCollection;
var authenticatedUser = serviceCollection.GetRequiredService<AuthenticatedUser>();
/*
Provide OpenID/MSAL code to authenticate the user. See your identity provider's
documentation for details.
The user is represented by a new ClaimsPrincipal based on a new ClaimsIdentity.
*/
var user = new ClaimsPrincipal(new ClaimsIdentity());
authenticatedUser.Principal = user;
Creare una classe AuthenticationStateProvider
personalizzata con gli aggiornamenti delle modifiche utente
Per aggiornare l'utente durante l'esecuzione dell'app Blazor, chiamare NotifyAuthenticationStateChanged all'interno dell'implementazione di AuthenticationStateProvider usando uno dei due approcci seguenti:
- Segnalare un aggiornamento dell'autenticazione dall'esterno di
BlazorWebView
) - Gestire l'autenticazione all'interno di
BlazorWebView
Segnalare un aggiornamento dell'autenticazione dall'esterno di BlazorWebView
(opzione 1)
Una classe AuthenticationStateProvider personalizzata può usare un servizio globale per segnalare un aggiornamento dell'autenticazione. È consigliabile che il servizio offra un evento che AuthenticationStateProvider possa sottoscrivere, dove l'evento richiama NotifyAuthenticationStateChanged.
Nota
La classe AuthenticationStateProvider personalizzata seguente non dichiara uno spazio dei nomi per fare in modo che l'esempio di codice sia applicabile a qualsiasi app Blazor Hybrid. È tuttavia consigliabile specificare lo spazio dei nomi dell'app quando si implementa l'esempio in un'app di produzione.
ExternalAuthStateProvider.cs
:
using System;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Authorization;
public class ExternalAuthStateProvider : AuthenticationStateProvider
{
private AuthenticationState currentUser;
public ExternalAuthStateProvider(ExternalAuthService service)
{
currentUser = new AuthenticationState(service.CurrentUser);
service.UserChanged += (newUser) =>
{
currentUser = new AuthenticationState(newUser);
NotifyAuthenticationStateChanged(Task.FromResult(currentUser));
};
}
public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
Task.FromResult(currentUser);
}
public class ExternalAuthService
{
public event Action<ClaimsPrincipal>? UserChanged;
private ClaimsPrincipal? currentUser;
public ClaimsPrincipal CurrentUser
{
get { return currentUser ?? new(); }
set
{
currentUser = value;
if (UserChanged is not null)
{
UserChanged(currentUser);
}
}
}
}
Nel metodo MauiProgram.CreateMauiApp
di MauiProgram.cs
aggiungere uno spazio dei nomi per Microsoft.AspNetCore.Components.Authorization:
using Microsoft.AspNetCore.Components.Authorization;
Aggiungere i servizi di autorizzazione e le astrazioni di Blazor alla raccolta di servizi:
builder.Services.AddAuthorizationCore();
builder.Services.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
builder.Services.AddSingleton<ExternalAuthService>();
Nel costruttore di MainWindow
(MainWindow.xaml.cs
) aggiungere uno spazio dei nomi per Microsoft.AspNetCore.Components.Authorization:
using Microsoft.AspNetCore.Components.Authorization;
Aggiungere i servizi di autorizzazione e le astrazioni di Blazor alla raccolta di servizi:
serviceCollection.AddAuthorizationCore();
serviceCollection.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
serviceCollection.AddSingleton<ExternalAuthService>();
Nel costruttore di Form1
(Form1.cs
) aggiungere uno spazio dei nomi per Microsoft.AspNetCore.Components.Authorization:
using Microsoft.AspNetCore.Components.Authorization;
Aggiungere i servizi di autorizzazione e le astrazioni di Blazor alla raccolta di servizi:
services.AddAuthorizationCore();
services.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
services.AddSingleton<ExternalAuthService>();
Ovunque l'app autentichi un utente, risolvere il servizio ExternalAuthService
:
var authService = host.Services.GetRequiredService<ExternalAuthService>();
Eseguire il codice OpenID/MSAL personalizzato per autenticare l'utente. Per informazioni dettagliate, vedere la identity documentazione del provider. L'utente autenticato (authenticatedUser
nell'esempio seguente) è una nuova classe ClaimsPrincipal basata su una nuova classe ClaimsIdentity.
Impostare l'utente corrente sull'utente autenticato:
authService.CurrentUser = authenticatedUser;
Un'alternativa all'approccio precedente consiste nell'impostare l'entità di sicurezza dell'utente su System.Threading.Thread.CurrentPrincipal invece di impostarla tramite un servizio, evitando l'uso del contenitore di inserimento delle dipendenze:
public class CurrentThreadUserAuthenticationStateProvider : AuthenticationStateProvider
{
public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
Task.FromResult(
new AuthenticationState(Thread.CurrentPrincipal as ClaimsPrincipal ??
new ClaimsPrincipal(new ClaimsIdentity())));
}
Usando l'approccio alternativo, vengono aggiunti alla raccolta di servizi solo i servizi di autorizzazione (AddAuthorizationCore) e CurrentThreadUserAuthenticationStateProvider
(.TryAddScoped<AuthenticationStateProvider, CurrentThreadUserAuthenticationStateProvider>()
).
Gestire l'autenticazione all'interno di BlazorWebView
(opzione 2)
Una classe AuthenticationStateProvider personalizzata può includere metodi aggiuntivi per attivare l'accesso e la disconnessione e aggiornare l'utente.
Nota
La classe AuthenticationStateProvider personalizzata seguente non dichiara uno spazio dei nomi per fare in modo che l'esempio di codice sia applicabile a qualsiasi app Blazor Hybrid. È tuttavia consigliabile specificare lo spazio dei nomi dell'app quando si implementa l'esempio in un'app di produzione.
ExternalAuthStateProvider.cs
:
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Authorization;
public class ExternalAuthStateProvider : AuthenticationStateProvider
{
private ClaimsPrincipal currentUser = new ClaimsPrincipal(new ClaimsIdentity());
public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
Task.FromResult(new AuthenticationState(currentUser));
public Task LogInAsync()
{
var loginTask = LogInAsyncCore();
NotifyAuthenticationStateChanged(loginTask);
return loginTask;
async Task<AuthenticationState> LogInAsyncCore()
{
var user = await LoginWithExternalProviderAsync();
currentUser = user;
return new AuthenticationState(currentUser);
}
}
private Task<ClaimsPrincipal> LoginWithExternalProviderAsync()
{
/*
Provide OpenID/MSAL code to authenticate the user. See your identity
provider's documentation for details.
Return a new ClaimsPrincipal based on a new ClaimsIdentity.
*/
var authenticatedUser = new ClaimsPrincipal(new ClaimsIdentity());
return Task.FromResult(authenticatedUser);
}
public void Logout()
{
currentUser = new ClaimsPrincipal(new ClaimsIdentity());
NotifyAuthenticationStateChanged(
Task.FromResult(new AuthenticationState(currentUser)));
}
}
Nell'esempio precedente:
- La chiamata a
LogInAsyncCore
attiva il processo di accesso. - La chiamata a NotifyAuthenticationStateChanged notifica che è in corso un aggiornamento, che consente all'app di fornire un'interfaccia utente temporanea durante il processo di accesso o disconnessione.
- La restituzione di
loginTask
restituisce l'attività in modo che il componente che ha attivato l'accesso possa attendere e reagire al termine dell'attività. - Il
LoginWithExternalProviderAsync
metodo viene implementato dallo sviluppatore per accedere all'utente con l'SDK identity del provider. Per altre informazioni, vedere la identity documentazione del provider. L'utente autenticato (authenticatedUser
) è una nuova classe ClaimsPrincipal basata su una nuova classe ClaimsIdentity.
Nel metodo MauiProgram.CreateMauiApp
di MauiProgram.cs
aggiungere i servizi di autorizzazione e l'astrazione di Blazor alla raccolta di servizi:
builder.Services.AddAuthorizationCore();
builder.Services.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
Nel costruttore di MainWindow
(MainWindow.xaml.cs
) aggiungere i servizi di autorizzazione e l'astrazione di Blazor alla raccolta di servizi:
serviceCollection.AddAuthorizationCore();
serviceCollection.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
Nel costruttore di Form1
(Form1.cs
) aggiungere i servizi di autorizzazione e l'astrazione di Blazor alla raccolta di servizi:
services.AddAuthorizationCore();
services.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
Il componente LoginComponent
seguente mostra come far accedere un utente. In un'app tipica il componente LoginComponent
viene visualizzato in un componente padre solo se l'utente non è connesso all'app.
Shared/LoginComponent.razor
:
@inject AuthenticationStateProvider AuthenticationStateProvider
<button @onclick="Login">Log in</button>
@code
{
public async Task Login()
{
await ((ExternalAuthStateProvider)AuthenticationStateProvider)
.LogInAsync();
}
}
Il componente LogoutComponent
seguente mostra come disconnettere un utente. In un'app tipica il componente LogoutComponent
viene visualizzato in un componente padre solo se l'utente è connesso all'app.
Shared/LogoutComponent.razor
:
@inject AuthenticationStateProvider AuthenticationStateProvider
<button @onclick="Logout">Log out</button>
@code
{
public async Task Logout()
{
await ((ExternalAuthStateProvider)AuthenticationStateProvider)
.Logout();
}
}
Accesso ad altre informazioni di autenticazione
Blazor non definisce un'astrazione per gestire altre credenziali, ad esempio i token di accesso da usare per le richieste HTTP alle API Web. È consigliabile seguire le identity indicazioni del provider per gestire le credenziali dell'utente con le primitive fornite dall'SDK identity del provider.
È comune che gli identity SDK del provider usino un archivio token per le credenziali utente archiviate nel dispositivo. Se la primitiva dell'archivio dei token dell'SDK viene aggiunta al contenitore di servizi, utilizzare la primitiva dell'SDK all'interno dell'app.
Il framework Blazor non è a conoscenza delle credenziali di autenticazione di un utente e non interagisce con le credenziali in alcun modo, quindi il codice dell'app è libero di seguire qualsiasi approccio ritenuto più pratico. Seguire tuttavia le indicazioni generali sulla sicurezza nella sezione successiva, Altre considerazioni sulla sicurezza dell'autenticazione, quando si implementa il codice di autenticazione in un'app.
Altre considerazioni sulla sicurezza dell'autenticazione
Il processo di autenticazione è esterno a Blazore si consiglia agli sviluppatori di accedere alle identity linee guida del provider per indicazioni aggiuntive sulla sicurezza.
Quando si implementa l'autenticazione:
- Evitare l'autenticazione nel contesto di Web View. Evitare, ad esempio, di usare una libreria OAuth JavaScript per eseguire il flusso di autenticazione. In un'app a pagina singola i token di autenticazione non sono nascosti in JavaScript e possono essere facilmente individuati da utenti malintenzionati e usati per scopi dannosi. Le app native non corrono questo rischio perché possono ottenere i token solo all'esterno del contesto del browser, quindi gli script di terze parti non autorizzati non possono rubare i token e compromettere l'app.
- Evitare di implementare manualmente il flusso di lavoro di autenticazione. Nella maggior parte dei casi, le librerie della piattaforma gestiscono in modo sicuro il flusso di lavoro di autenticazione, usando il browser del sistema invece di una Web View personalizzata che può essere soggetta a hijack.
- Evitare di usare il controllo Web View della piattaforma per eseguire l'autenticazione. Fare invece affidamento sul browser del sistema, quando possibile.
- Evitare di passare i token al contesto del documento (JavaScript). In alcuni casi, è necessaria una libreria JavaScript all'interno del documento per eseguire una chiamata autorizzata a un servizio esterno. Invece di rendere il token disponibile per JavaScript tramite JS interoperabilità:
- Fornire un token temporaneo generato alla libreria e all'interno del controllo Web View.
- Intercettare la richiesta di rete in uscita nel codice.
- Sostituire il token temporaneo con il token reale e verificare che la destinazione della richiesta sia valida.
Risorse aggiuntive
- Autenticazione e autorizzazione per ASP.NET Core Blazor
- Considerazioni sulla sicurezza di ASP.NET Core Blazor Hybrid
- Documentazione relativa all'ID Entra per .NET MAUI
- Documentazione di Azure per .NET MAUI
L'autenticazione nelle app Blazor Hybrid viene gestita dalle librerie della piattaforma nativa perché offrono garanzie di sicurezza avanzata che la sandbox del browser non può offrire. L'autenticazione delle app native usa un meccanismo specifico del sistema operativo o un protocollo federato, ad esempio OpenID Connect (OIDC). Seguire le indicazioni per il identity provider selezionato per l'app e quindi integrarsi identity ulteriormente con Blazor l'uso delle indicazioni riportate in questo articolo.
L'integrazione dell'autenticazione deve raggiungere gli obiettivi seguenti per i componenti e i servizi di Razor:
- Usare le astrazioni nel pacchetto
Microsoft.AspNetCore.Components.Authorization
, ad esempio AuthorizeView. - Reagire alle modifiche nel contesto di autenticazione.
- Credenziali di accesso di cui viene effettuato il identity provisioning dall'app dal provider, ad esempio i token di accesso per eseguire chiamate API autorizzate.
Dopo che l'autenticazione è stata aggiunta a un'app .NET MAUI, WPF o Windows Form e gli utenti possono accedere e disconnettersi correttamente, integrare l'autenticazione con Blazor per rendere l'utente autenticato disponibile per i componenti e i servizi di Razor. Procedi come segue:
Fare riferimento al pacchetto
Microsoft.AspNetCore.Components.Authorization
.Nota
Per indicazioni sull'aggiunta di pacchetti alle app .NET, vedere gli articoli sotto Installare e gestire pacchetti in Flusso di lavoro dell'utilizzo di pacchetti (documentazione di NuGet). Confermare le versioni corrette del pacchetto all'indirizzo NuGet.org.
Implementare una classe AuthenticationStateProvider personalizzata, ovvero l'astrazione usata dai componenti di Razor per accedere alle informazioni sull'utente autenticato e per ricevere gli aggiornamenti quando lo stato dell'autenticazione cambia.
Registrare il provider di stato dell'autenticazione personalizzata nel contenitore di inserimento delle dipendenze.
Le app .NET MAUI usano l'autenticatore Web di Xamarin.Essentials: la classe WebAuthenticator
consente all'app di avviare i flussi di autenticazione basata sul browser che sono in ascolto di un callback a un URL specifico registrato con l'app.
Per altre indicazioni, vedere le risorse seguenti:
Le app WPF usano la piattaforma Microsoft identity per l'integrazione con Microsoft Entra (ME-ID) e AAD B2C. Per indicazioni ed esempi, vedere le risorse seguenti:
- Panoramica di Microsoft Authentication Library (MSAL)
- Aggiungere l'autenticazione all'app Windows (WPF)
- Esercitazione: Far accedere gli utenti e chiamare Microsoft Graph nell'app desktop Windows Presentation Foundation (WPF)
- Avvio rapido: Acquisire un token e chiamare l'API Microsoft Graph da un'applicazione desktop
- Avvio rapido: Configurare l'accesso per un'app desktop tramite Azure Active Directory B2C
- Configurare l'autenticazione in un'app desktop WPF di esempio usando Azure AD B2C
Windows Form le app usano Piattaforma Microsoft identity da integrare con Microsoft Entra (ME-ID) e AAD B2C. Per altre informazioni, vedere Panoramica di Microsoft Authentication Library (MSAL).
Creare una classe AuthenticationStateProvider
personalizzata senza aggiornamenti delle modifiche utente
Se l'app autentica l'utente immediatamente dopo l'avvio dell'app e l'utente autenticato rimane lo stesso per tutta la durata dell'app, le notifiche di modifica utente non sono necessarie e l'app fornisce solo informazioni sull'utente autenticato. In questo scenario l'utente accede all'app quando l'app viene aperta e l'app visualizza nuovamente la schermata di accesso dopo la disconnessione dell'utente. L'elemento ExternalAuthStateProvider
seguente è un'implementazione di esempio di una classe AuthenticationStateProvider personalizzata per questo scenario di autenticazione.
Nota
La classe AuthenticationStateProvider personalizzata seguente non dichiara uno spazio dei nomi per fare in modo che l'esempio di codice sia applicabile a qualsiasi app Blazor Hybrid. È tuttavia consigliabile specificare lo spazio dei nomi dell'app quando si implementa l'esempio in un'app di produzione.
ExternalAuthStateProvider.cs
:
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Authorization;
public class ExternalAuthStateProvider : AuthenticationStateProvider
{
private readonly Task<AuthenticationState> authenticationState;
public ExternalAuthStateProvider(AuthenticatedUser user) =>
authenticationState = Task.FromResult(new AuthenticationState(user.Principal));
public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
authenticationState;
}
public class AuthenticatedUser
{
public ClaimsPrincipal Principal { get; set; } = new();
}
Nei passaggi successivi viene descritto come effettuare le seguenti operazioni:
- Aggiungere gli spazi dei nomi obbligatori.
- Aggiungere i servizi di autorizzazione e le astrazioni di Blazor alla raccolta di servizi.
- Compilare la raccolta di servizi.
- Risolvere il servizio
AuthenticatedUser
per impostare l'entità di sicurezza delle attestazioni dell'utente autenticato. Per informazioni dettagliate, vedere la identity documentazione del provider. - Restituire l'host compilato.
Nel metodo MauiProgram.CreateMauiApp
di MauiProgram.cs
aggiungere gli spazi dei nomi per Microsoft.AspNetCore.Components.Authorization e System.Security.Claims:
using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;
Rimuovere la riga di codice seguente che restituisce un elemento Microsoft.Maui.Hosting.MauiApp compilato:
- return builder.Build();
Sostituire la riga di codice precedente con il codice seguente. Aggiungere il codice OpenID/MSAL per autenticare l'utente. Per informazioni dettagliate, vedere la identity documentazione del provider.
builder.Services.AddAuthorizationCore();
builder.Services.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
builder.Services.AddSingleton<AuthenticatedUser>();
var host = builder.Build();
var authenticatedUser = host.Services.GetRequiredService<AuthenticatedUser>();
/*
Provide OpenID/MSAL code to authenticate the user. See your identity provider's
documentation for details.
The user is represented by a new ClaimsPrincipal based on a new ClaimsIdentity.
*/
var user = new ClaimsPrincipal(new ClaimsIdentity());
authenticatedUser.Principal = user;
return host;
Nei passaggi successivi viene descritto come effettuare le seguenti operazioni:
- Aggiungere gli spazi dei nomi obbligatori.
- Aggiungere i servizi di autorizzazione e le astrazioni di Blazor alla raccolta di servizi.
- Compilare la raccolta di servizi e aggiungere la raccolta di servizi compilata come risorsa al
ResourceDictionary
dell'app. - Risolvere il servizio
AuthenticatedUser
per impostare l'entità di sicurezza delle attestazioni dell'utente autenticato. Per informazioni dettagliate, vedere la identity documentazione del provider. - Restituire l'host compilato.
Nel costruttore di MainWindow
(MainWindow.xaml.cs
) aggiungere gli spazi dei nomi per Microsoft.AspNetCore.Components.Authorization e System.Security.Claims:
using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;
Rimuovere la riga di codice seguente che aggiunge la raccolta di servizi compilata come risorsa al ResourceDictionary
dell'app:
- Resources.Add("services", serviceCollection.BuildServiceProvider());
Sostituire la riga di codice precedente con il codice seguente. Aggiungere il codice OpenID/MSAL per autenticare l'utente. Per informazioni dettagliate, vedere la identity documentazione del provider.
serviceCollection.AddAuthorizationCore();
serviceCollection.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
serviceCollection.AddSingleton<AuthenticatedUser>();
var services = serviceCollection.BuildServiceProvider();
Resources.Add("services", services);
var authenticatedUser = services.GetRequiredService<AuthenticatedUser>();
/*
Provide OpenID/MSAL code to authenticate the user. See your identity provider's
documentation for details.
The user is represented by a new ClaimsPrincipal based on a new ClaimsIdentity.
*/
var user = new ClaimsPrincipal(new ClaimsIdentity());
authenticatedUser.Principal = user;
Nei passaggi successivi viene descritto come effettuare le seguenti operazioni:
- Aggiungere gli spazi dei nomi obbligatori.
- Aggiungere i servizi di autorizzazione e le astrazioni di Blazor alla raccolta di servizi.
- Compilare la raccolta di servizi e aggiungere la raccolta di servizi compilata al provider di servizi dell'app.
- Risolvere il servizio
AuthenticatedUser
per impostare l'entità di sicurezza delle attestazioni dell'utente autenticato. Per informazioni dettagliate, vedere la identity documentazione del provider.
Nel costruttore di Form1
(Form1.cs
) aggiungere gli spazi dei nomi per Microsoft.AspNetCore.Components.Authorization e System.Security.Claims:
using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;
Rimuovere la riga di codice seguente che imposta la raccolta di servizi compilata sul provider di servizi dell'app:
- blazorWebView1.Services = services.BuildServiceProvider();
Sostituire la riga di codice precedente con il codice seguente. Aggiungere il codice OpenID/MSAL per autenticare l'utente. Per informazioni dettagliate, vedere la identity documentazione del provider.
services.AddAuthorizationCore();
services.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
services.AddSingleton<AuthenticatedUser>();
var serviceCollection = services.BuildServiceProvider();
blazorWebView1.Services = serviceCollection;
var authenticatedUser = serviceCollection.GetRequiredService<AuthenticatedUser>();
/*
Provide OpenID/MSAL code to authenticate the user. See your identity provider's
documentation for details.
The user is represented by a new ClaimsPrincipal based on a new ClaimsIdentity.
*/
var user = new ClaimsPrincipal(new ClaimsIdentity());
authenticatedUser.Principal = user;
Creare una classe AuthenticationStateProvider
personalizzata con gli aggiornamenti delle modifiche utente
Per aggiornare l'utente durante l'esecuzione dell'app Blazor, chiamare NotifyAuthenticationStateChanged all'interno dell'implementazione di AuthenticationStateProvider usando uno dei due approcci seguenti:
- Segnalare un aggiornamento dell'autenticazione dall'esterno di
BlazorWebView
) - Gestire l'autenticazione all'interno di
BlazorWebView
Segnalare un aggiornamento dell'autenticazione dall'esterno di BlazorWebView
(opzione 1)
Una classe AuthenticationStateProvider personalizzata può usare un servizio globale per segnalare un aggiornamento dell'autenticazione. È consigliabile che il servizio offra un evento che AuthenticationStateProvider possa sottoscrivere, dove l'evento richiama NotifyAuthenticationStateChanged.
Nota
La classe AuthenticationStateProvider personalizzata seguente non dichiara uno spazio dei nomi per fare in modo che l'esempio di codice sia applicabile a qualsiasi app Blazor Hybrid. È tuttavia consigliabile specificare lo spazio dei nomi dell'app quando si implementa l'esempio in un'app di produzione.
ExternalAuthStateProvider.cs
:
using System;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Authorization;
public class ExternalAuthStateProvider : AuthenticationStateProvider
{
private AuthenticationState currentUser;
public ExternalAuthStateProvider(ExternalAuthService service)
{
currentUser = new AuthenticationState(service.CurrentUser);
service.UserChanged += (newUser) =>
{
currentUser = new AuthenticationState(newUser);
NotifyAuthenticationStateChanged(Task.FromResult(currentUser));
};
}
public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
Task.FromResult(currentUser);
}
public class ExternalAuthService
{
public event Action<ClaimsPrincipal>? UserChanged;
private ClaimsPrincipal? currentUser;
public ClaimsPrincipal CurrentUser
{
get { return currentUser ?? new(); }
set
{
currentUser = value;
if (UserChanged is not null)
{
UserChanged(currentUser);
}
}
}
}
Nel metodo MauiProgram.CreateMauiApp
di MauiProgram.cs
aggiungere uno spazio dei nomi per Microsoft.AspNetCore.Components.Authorization:
using Microsoft.AspNetCore.Components.Authorization;
Aggiungere i servizi di autorizzazione e le astrazioni di Blazor alla raccolta di servizi:
builder.Services.AddAuthorizationCore();
builder.Services.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
builder.Services.AddSingleton<ExternalAuthService>();
Nel costruttore di MainWindow
(MainWindow.xaml.cs
) aggiungere uno spazio dei nomi per Microsoft.AspNetCore.Components.Authorization:
using Microsoft.AspNetCore.Components.Authorization;
Aggiungere i servizi di autorizzazione e le astrazioni di Blazor alla raccolta di servizi:
serviceCollection.AddAuthorizationCore();
serviceCollection.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
serviceCollection.AddSingleton<ExternalAuthService>();
Nel costruttore di Form1
(Form1.cs
) aggiungere uno spazio dei nomi per Microsoft.AspNetCore.Components.Authorization:
using Microsoft.AspNetCore.Components.Authorization;
Aggiungere i servizi di autorizzazione e le astrazioni di Blazor alla raccolta di servizi:
services.AddAuthorizationCore();
services.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
services.AddSingleton<ExternalAuthService>();
Ovunque l'app autentichi un utente, risolvere il servizio ExternalAuthService
:
var authService = host.Services.GetRequiredService<ExternalAuthService>();
Eseguire il codice OpenID/MSAL personalizzato per autenticare l'utente. Per informazioni dettagliate, vedere la identity documentazione del provider. L'utente autenticato (authenticatedUser
nell'esempio seguente) è una nuova classe ClaimsPrincipal basata su una nuova classe ClaimsIdentity.
Impostare l'utente corrente sull'utente autenticato:
authService.CurrentUser = authenticatedUser;
Un'alternativa all'approccio precedente consiste nell'impostare l'entità di sicurezza dell'utente su System.Threading.Thread.CurrentPrincipal invece di impostarla tramite un servizio, evitando l'uso del contenitore di inserimento delle dipendenze:
public class CurrentThreadUserAuthenticationStateProvider : AuthenticationStateProvider
{
public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
Task.FromResult(
new AuthenticationState(Thread.CurrentPrincipal as ClaimsPrincipal ??
new ClaimsPrincipal(new ClaimsIdentity())));
}
Usando l'approccio alternativo, vengono aggiunti alla raccolta di servizi solo i servizi di autorizzazione (AddAuthorizationCore) e CurrentThreadUserAuthenticationStateProvider
(.AddScoped<AuthenticationStateProvider, CurrentThreadUserAuthenticationStateProvider>()
).
Gestire l'autenticazione all'interno di BlazorWebView
(opzione 2)
Una classe AuthenticationStateProvider personalizzata può includere metodi aggiuntivi per attivare l'accesso e la disconnessione e aggiornare l'utente.
Nota
La classe AuthenticationStateProvider personalizzata seguente non dichiara uno spazio dei nomi per fare in modo che l'esempio di codice sia applicabile a qualsiasi app Blazor Hybrid. È tuttavia consigliabile specificare lo spazio dei nomi dell'app quando si implementa l'esempio in un'app di produzione.
ExternalAuthStateProvider.cs
:
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Authorization;
public class ExternalAuthStateProvider : AuthenticationStateProvider
{
private ClaimsPrincipal currentUser = new ClaimsPrincipal(new ClaimsIdentity());
public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
Task.FromResult(new AuthenticationState(currentUser));
public Task LogInAsync()
{
var loginTask = LogInAsyncCore();
NotifyAuthenticationStateChanged(loginTask);
return loginTask;
async Task<AuthenticationState> LogInAsyncCore()
{
var user = await LoginWithExternalProviderAsync();
currentUser = user;
return new AuthenticationState(currentUser);
}
}
private Task<ClaimsPrincipal> LoginWithExternalProviderAsync()
{
/*
Provide OpenID/MSAL code to authenticate the user. See your identity
provider's documentation for details.
Return a new ClaimsPrincipal based on a new ClaimsIdentity.
*/
var authenticatedUser = new ClaimsPrincipal(new ClaimsIdentity());
return Task.FromResult(authenticatedUser);
}
public void Logout()
{
currentUser = new ClaimsPrincipal(new ClaimsIdentity());
NotifyAuthenticationStateChanged(
Task.FromResult(new AuthenticationState(currentUser)));
}
}
Nell'esempio precedente:
- La chiamata a
LogInAsyncCore
attiva il processo di accesso. - La chiamata a NotifyAuthenticationStateChanged notifica che è in corso un aggiornamento, che consente all'app di fornire un'interfaccia utente temporanea durante il processo di accesso o disconnessione.
- La restituzione di
loginTask
restituisce l'attività in modo che il componente che ha attivato l'accesso possa attendere e reagire al termine dell'attività. - Il
LoginWithExternalProviderAsync
metodo viene implementato dallo sviluppatore per accedere all'utente con l'SDK identity del provider. Per altre informazioni, vedere la identity documentazione del provider. L'utente autenticato (authenticatedUser
) è una nuova classe ClaimsPrincipal basata su una nuova classe ClaimsIdentity.
Nel metodo MauiProgram.CreateMauiApp
di MauiProgram.cs
aggiungere i servizi di autorizzazione e l'astrazione di Blazor alla raccolta di servizi:
builder.Services.AddAuthorizationCore();
builder.Services.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
Nel costruttore di MainWindow
(MainWindow.xaml.cs
) aggiungere i servizi di autorizzazione e l'astrazione di Blazor alla raccolta di servizi:
serviceCollection.AddAuthorizationCore();
serviceCollection.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
Nel costruttore di Form1
(Form1.cs
) aggiungere i servizi di autorizzazione e l'astrazione di Blazor alla raccolta di servizi:
services.AddAuthorizationCore();
services.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
Il componente LoginComponent
seguente mostra come far accedere un utente. In un'app tipica il componente LoginComponent
viene visualizzato in un componente padre solo se l'utente non è connesso all'app.
Shared/LoginComponent.razor
:
@inject AuthenticationStateProvider AuthenticationStateProvider
<button @onclick="Login">Log in</button>
@code
{
public async Task Login()
{
await ((ExternalAuthStateProvider)AuthenticationStateProvider)
.LogInAsync();
}
}
Il componente LogoutComponent
seguente mostra come disconnettere un utente. In un'app tipica il componente LogoutComponent
viene visualizzato in un componente padre solo se l'utente è connesso all'app.
Shared/LogoutComponent.razor
:
@inject AuthenticationStateProvider AuthenticationStateProvider
<button @onclick="Logout">Log out</button>
@code
{
public async Task Logout()
{
await ((ExternalAuthStateProvider)AuthenticationStateProvider)
.Logout();
}
}
Accesso ad altre informazioni di autenticazione
Blazor non definisce un'astrazione per gestire altre credenziali, ad esempio i token di accesso da usare per le richieste HTTP alle API Web. È consigliabile seguire le identity indicazioni del provider per gestire le credenziali dell'utente con le primitive fornite dall'SDK identity del provider.
È comune che gli identity SDK del provider usino un archivio token per le credenziali utente archiviate nel dispositivo. Se la primitiva dell'archivio dei token dell'SDK viene aggiunta al contenitore di servizi, utilizzare la primitiva dell'SDK all'interno dell'app.
Il framework Blazor non è a conoscenza delle credenziali di autenticazione di un utente e non interagisce con le credenziali in alcun modo, quindi il codice dell'app è libero di seguire qualsiasi approccio ritenuto più pratico. Seguire tuttavia le indicazioni generali sulla sicurezza nella sezione successiva, Altre considerazioni sulla sicurezza dell'autenticazione, quando si implementa il codice di autenticazione in un'app.
Altre considerazioni sulla sicurezza dell'autenticazione
Il processo di autenticazione è esterno a Blazore si consiglia agli sviluppatori di accedere alle identity linee guida del provider per indicazioni aggiuntive sulla sicurezza.
Quando si implementa l'autenticazione:
- Evitare l'autenticazione nel contesto di Web View. Evitare, ad esempio, di usare una libreria OAuth JavaScript per eseguire il flusso di autenticazione. In un'app a pagina singola i token di autenticazione non sono nascosti in JavaScript e possono essere facilmente individuati da utenti malintenzionati e usati per scopi dannosi. Le app native non corrono questo rischio perché possono ottenere i token solo all'esterno del contesto del browser, quindi gli script di terze parti non autorizzati non possono rubare i token e compromettere l'app.
- Evitare di implementare manualmente il flusso di lavoro di autenticazione. Nella maggior parte dei casi, le librerie della piattaforma gestiscono in modo sicuro il flusso di lavoro di autenticazione, usando il browser del sistema invece di una Web View personalizzata che può essere soggetta a hijack.
- Evitare di usare il controllo Web View della piattaforma per eseguire l'autenticazione. Fare invece affidamento sul browser del sistema, quando possibile.
- Evitare di passare i token al contesto del documento (JavaScript). In alcuni casi, è necessaria una libreria JavaScript all'interno del documento per eseguire una chiamata autorizzata a un servizio esterno. Invece di rendere il token disponibile per JavaScript tramite JS interoperabilità:
- Fornire un token temporaneo generato alla libreria e all'interno del controllo Web View.
- Intercettare la richiesta di rete in uscita nel codice.
- Sostituire il token temporaneo con il token reale e verificare che la destinazione della richiesta sia valida.