Share via


Proteggere un'app Web core Blazor di ASP.NET con OpenID Connessione (OIDC)

Questo articolo descrive come proteggere un'app Blazor Web con OpenID Connessione (OIDC) usando un'app di esempio nel dotnet/blazor-samples repository GitHub (.NET 8 o versione successiva) (come scaricare).

Questa versione dell'articolo illustra l'implementazione di OIDC senza adottare il modello Back-end per front-end (BFF). Il modello BFF è utile per effettuare richieste autenticate a servizi esterni. Modificare il selettore di versione dell'articolo in OIDC con modello BFF se la specifica dell'app richiede l'adozione del modello BFF.

La specifica seguente è descritta:

  • L'app Blazor Web usa la modalità di rendering automatico con interattività globale.
  • I servizi provider di stato di autenticazione personalizzati vengono usati dal server e dalle app client per acquisire lo stato di autenticazione dell'utente e fluirlo tra il server e il client.
  • Questa app è un punto di partenza per qualsiasi flusso di autenticazione OIDC. OIDC viene configurato manualmente nell'app e non si basa su Microsoft Entra ID o pacchetti Web MicrosoftIdentity, né l'app di esempio richiede l'hosting di Microsoft Azure. Tuttavia, l'app di esempio può essere usata con Entra, Microsoft Identity Web e ospitata in Azure.
  • Aggiornamento automatico del token non interattivo.
  • Chiama in modo sicuro un'API (Web) nel progetto server per i dati.

Esempio di app

L'app di esempio è costituita da due progetti:

  • BlazorWebAppOidc: progetto lato server dell'app Blazor Web contenente un esempio di endpoint API minimo per i dati meteo.
  • BlazorWebAppOidc.Client: progetto lato client dell'app Blazor Web.

Accedere alle app di esempio tramite la cartella della versione più recente dalla radice del repository con il collegamento seguente. I progetti si trovano nella BlazorWebAppOidc cartella per .NET 8 o versione successiva.

Visualizzare o scaricare il codice di esempio (procedura per il download)

Progetto app Web sul lato Blazor server (BlazorWebAppOidc)

Il BlazorWebAppOidc progetto è il progetto lato server dell'app Blazor Web.

Il BlazorWebAppOidc.http file può essere usato per testare la richiesta di dati meteo. Si noti che il BlazorWebAppOidc progetto deve essere in esecuzione per testare l'endpoint e l'endpoint è hardcoded nel file. Per altre informazioni, vedere Usare file .http in Visual Studio 2022.

Nota

Il progetto server usa IHttpContextAccessor/HttpContext, ma non per i componenti di cui è stato eseguito il rendering interattivo. Per altre informazioni, vedere Linee guida per la mitigazione delle minacce per ASP.NET rendering lato server interattivo CoreBlazor.

Impostazione

Questa sezione illustra come configurare l'app di esempio.

Nota

Per Microsoft Entra ID e Azure AD B2C, è possibile usare microsoft AddMicrosoftIdentityWebAppIdentityWeb (Microsoft.Identity.Web pacchetto NuGet, documentazione dell'API), che aggiunge sia i gestori OIDC Cookie che i gestori di autenticazione con le impostazioni predefinite appropriate. L'app di esempio e le indicazioni contenute in questa sezione non usano Microsoft Identity Web. Le linee guida illustrano come configurare manualmente il gestore OIDC per qualsiasi provider OIDC. Per altre informazioni sull'implementazione di Microsoft Identity Web, vedere le risorse collegate.

La configurazione seguente OpenIdConnectOptions è disponibile nel file del Program progetto nella chiamata a AddOpenIdConnect:

  • SignInScheme: imposta lo schema di autenticazione corrispondente al middleware responsabile della persistenza dell'identità dell'utente dopo un'autenticazione riuscita. Il gestore OIDC deve usare uno schema di accesso in grado di rendere persistenti le credenziali utente tra le richieste. La seguente riga è presente solo a scopo dimostrativo. Se omesso, DefaultSignInScheme viene usato come valore di fallback.

    oidcOptions.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    
  • Ambiti per openid e () (Scopefacoltativo): anche gli openid ambiti e profileprofile sono configurati per impostazione predefinita perché sono necessari per il funzionamento del gestore OIDC, ma potrebbe essere necessario aggiungerli nuovamente se gli ambiti sono inclusi nella Authentication:Schemes:MicrosoftOidc:Scope configurazione. Per indicazioni generali sulla configurazione, vedere Configurazione in ASP.NET Core e configurazione di ASP.NET CoreBlazor.

    oidcOptions.Scope.Add(OpenIdConnectScope.OpenIdProfile);
    
  • SaveTokens: definisce se i token di accesso e aggiornamento devono essere archiviati in AuthenticationProperties dopo un'autorizzazione riuscita. Questa proprietà è impostata su false per impostazione predefinita per ridurre le dimensioni dell'autenticazione cookiefinale.

    oidcOptions.SaveTokens = false;
    
  • Ambito per l'accesso offline (Scope): l'ambito offline_access è obbligatorio per il token di aggiornamento.

    oidcOptions.Scope.Add(OpenIdConnectScope.OfflineAccess);
    
  • Authority e ClientId: imposta l'autorità e l'ID client per le chiamate OIDC.

    oidcOptions.Authority = "{AUTHORITY}";
    oidcOptions.ClientId = "{CLIENT ID}";
    

    Esempio:

    • Autorità (): https://login.microsoftonline.com/a3942615-d115-4eb7-bc84-9974abcf5064/v2.0/ ({AUTHORITY}usa l'ID a3942615-d115-4eb7-bc84-9974abcf5064tenant )
    • ID client ({CLIENT ID}): 4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f
    oidcOptions.Authority = "https://login.microsoftonline.com/a3942615-d115-4eb7-bc84-9974abcf5064/v2.0/";
    oidcOptions.ClientId = "4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f";
    

    Esempio per l'autorità "common" di Microsoft Azure:

    L'autorità "comune" deve essere usata per le app multi-tenant. È anche possibile usare l'autorità "comune" per le app a tenant singolo, ma è necessario un personalizzato IssuerValidator , come illustrato più avanti in questa sezione.

    oidcOptions.Authority = "https://login.microsoftonline.com/common/v2.0/";
    
  • ClientSecret: segreto client OIDC.

    L'esempio seguente è solo a scopo di test e dimostrazione. Non archiviare il segreto client nell'assembly dell'app o controllare il segreto nel controllo del codice sorgente. Archiviare il segreto client in Segreti utente, Azure Key Vault o una variabile di ambiente.

    La configurazione dello schema di autenticazione viene letta automaticamente da builder.Configuration["Authentication:Schemes:{SCHEME NAME}:{PropertyName}"], dove il {SCHEME NAME} segnaposto è lo schema, ovvero per MicrosoftOidc impostazione predefinita. Poiché la configurazione è preconfigurata, un segreto client può essere letto automaticamente tramite la Authentication:Schemes:MicrosoftOidc:ClientSecret chiave di configurazione. Nel server che usa variabili di ambiente assegnare alla variabile Authentication__Schemes__MicrosoftOidc__ClientSecretdi ambiente il nome :

    set Authentication__Schemes__MicrosoftOidc__ClientSecret={CLIENT SECRET}
    

    Solo per la dimostrazione e il test, ClientSecret è possibile impostare direttamente . Non impostare il valore direttamente per le app di produzione distribuite. Per una sicurezza leggermente migliorata, compilare in modo condizionale la riga con il DEBUG simbolo :

    #if DEBUG
    oidcOptions.ClientSecret = "{CLIENT SECRET}";
    #endif
    

    Esempio:

    Segreto client (): 463471c8c4...f90d674bc9 ({CLIENT SECRET}abbreviato per la visualizzazione)

    #if DEBUG
    oidcOptions.ClientSecret = "463471c8c4...137f90d674bc9";
    #endif
    
  • ResponseType: configura il gestore OIDC per eseguire solo il flusso del codice di autorizzazione. Le concessioni implicite e i flussi ibridi non sono necessari in questa modalità.

    Nella configurazione di registrazione dell'app Entra o portale di Azure implicita e dei flussi ibridi, non selezionare la casella di controllo per l'endpoint di autorizzazione per restituire token di accesso o token ID. Il gestore OIDC richiede automaticamente i token appropriati usando il codice restituito dall'endpoint di autorizzazione.

    oidcOptions.ResponseType = OpenIdConnectResponseType.Code;
    
  • MapInboundClaimse la configurazione di NameClaimType e : molti server OIDC usano "name" e "role" anziché le impostazioni predefinite SOAP/WS-Fed in ClaimTypesRoleClaimType. Quando MapInboundClaims è impostato su false, il gestore non esegue mapping delle attestazioni e i nomi delle attestazioni del token JWT vengono usati direttamente dall'app. L'esempio seguente esegue manualmente il mapping del nome e delle attestazioni del ruolo:

Nota

MapInboundClaims deve essere impostato su false per la maggior parte dei provider OIDC, che impedisce la ridenominazione delle attestazioni.

oidcOptions.MapInboundClaims = false;
oidcOptions.TokenValidationParameters.NameClaimType = JwtRegisteredClaimNames.Name;
oidcOptions.TokenValidationParameters.RoleClaimType = "role";
  • Configurazione del percorso: i percorsi devono corrispondere all'URI di reindirizzamento (percorso di callback di accesso) e ai percorsi di reindirizzamento post disconnessione (percorso di callback con disconnessione) configurati durante la registrazione dell'applicazione con il provider OIDC. Nel portale di Azure i percorsi vengono configurati nel pannello Autenticazione della registrazione dell'app. Entrambi i percorsi di accesso e disconnessione devono essere registrati come URI di reindirizzamento. I valori predefiniti sono /signin-oidc e /signout-callback-oidc.

    • CallbackPath: percorso della richiesta all'interno del percorso di base dell'app in cui viene restituito l'agente utente.

      In Entra o portale di Azure impostare il percorso nell'URI di reindirizzamento della configurazione della piattaforma Web:

      https://localhost/signin-oidc

      Nota

      Una porta non è necessaria per localhost gli indirizzi quando si usa Microsoft Entra ID. La maggior parte degli altri provider OIDC richiede una porta corretta.

    • SignedOutCallbackPath: percorso della richiesta all'interno del percorso di base dell'app in cui viene restituito l'agente utente dopo la disconnessione dal provider di identità.

      In Entra o portale di Azure impostare il percorso nell'URI di reindirizzamento della configurazione della piattaforma Web:

      https://localhost/signout-callback-oidc

      Nota

      Una porta non è necessaria per localhost gli indirizzi quando si usa Microsoft Entra ID. La maggior parte degli altri provider OIDC richiede una porta corretta.

      Nota

      Se si usa Microsoft Identity Web, il provider attualmente reindirizza di nuovo a SignedOutCallbackPath se viene usata l'autorità microsoftonline.com (https://login.microsoftonline.com/{TENANT ID}/v2.0/). Questa limitazione non esiste se è possibile usare l'autorità "comune" con Microsoft Identity Web. Per altre informazioni, vedere postLogoutRedirectUri not working when authority URL contains a tenant ID (AzureAD/microsoft-authentication-library-for-js #5783).

    • RemoteSignOutPath: le richieste ricevute in questo percorso causano il richiamo della disconnessione da parte del gestore tramite lo schema di disconnessione.

      In Entra o portale di Azure impostare l'URL di disconnessione del canale anteriore:

      https://localhost/signout-oidc

      Nota

      Una porta non è necessaria per localhost gli indirizzi quando si usa Microsoft Entra ID. La maggior parte degli altri provider OIDC richiede una porta corretta.

    oidcOptions.CallbackPath = new PathString("{PATH}");
    oidcOptions.SignedOutCallbackPath = new PathString("{PATH}");
    oidcOptions.RemoteSignOutPath = new PathString("{PATH}");
    

    Esempi (valori predefiniti):

    oidcOptions.CallbackPath = new PathString("/signin-oidc");
    oidcOptions.SignedOutCallbackPath = new PathString("/signout-callback-oidc");
    oidcOptions.RemoteSignOutPath = new PathString("/signout-oidc");
    
  • (Microsoft Azure solo con l'endpoint "comune") TokenValidationParameters.IssuerValidator: molti provider OIDC funzionano con il validator predefinito dell'autorità di certificazione, ma è necessario tenere conto dell'autorità di certificazione con parametri con l'ID tenant ({TENANT ID}) restituito da https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration. Per altre informazioni, vedere SecurityTokenInvalidIssuerException con OpenID Connessione e l'endpoint "common" di Azure AD (AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet #1731)..

    Solo per le app che usano Microsoft Entra ID o Azure AD B2C con l'endpoint "comune":

    var microsoftIssuerValidator = AadIssuerValidator.GetAadIssuerValidator(oidcOptions.Authority);
    oidcOptions.TokenValidationParameters.IssuerValidator = microsoftIssuerValidator.Validate;
    

Codice dell'app di esempio

Esaminare l'app di esempio per le funzionalità seguenti:

  • Aggiornamento automatico del token non interattivo con l'aiuto di un aggiornamento personalizzato cookie (CookieOidcRefresher.cs).
  • La PersistingAuthenticationStateProvider classe (PersistingAuthenticationStateProvider.cs) è un lato AuthenticationStateProvider server che usa PersistentComponentState per trasferire lo stato di autenticazione al client, che viene quindi risolto per la durata dell'applicazione WebAssembly.
  • Un esempio di richieste all'app Web per i Blazor dati meteo viene gestito da un endpoint API minimo (/weather-forecast) nel Program file (Program.cs). L'endpoint richiede l'autorizzazione chiamando RequireAuthorization. Per tutti i controller aggiunti al progetto, aggiungere l'attributo [Authorize] al controller o all'azione.
  • L'app chiama in modo sicuro un'API (Web) nel progetto server per i dati meteo:
    • Quando si esegue il rendering del Weather componente nel server, il componente usa sul ServerWeatherForecaster server per ottenere i dati meteo direttamente (non tramite una chiamata API Web).
    • Quando viene eseguito il rendering del componente nel client, il componente usa l'implementazione del ClientWeatherForecaster servizio, che usa un preconfigurato HttpClient (nel file del Program progetto client) per effettuare una chiamata API Web al progetto server. Un endpoint API minimo (/weather-forecast) definito nel file del progetto server Program ottiene i dati meteo da ServerWeatherForecaster e restituisce i dati al client.

Per altre informazioni sulle chiamate API (Web) tramite astrazioni di servizio in Blazor App Web, vedere Chiamare un'API Web da un'app ASP.NET CoreBlazor.

Progetto app Web sul lato Blazor client (BlazorWebAppOidc.Client)

Il BlazorWebAppOidc.Client progetto è il progetto lato client dell'app Blazor Web.

La PersistentAuthenticationStateProvider classe (PersistentAuthenticationStateProvider.cs) è un lato AuthenticationStateProvider client che determina lo stato di autenticazione dell'utente cercando i dati persistenti nella pagina quando è stato eseguito il rendering nel server. Lo stato di autenticazione è fisso per la durata dell'applicazione WebAssembly.

Se l'utente deve accedere o disconnettersi, è necessario ricaricare una pagina completa.

L'app di esempio fornisce solo un nome utente e un messaggio di posta elettronica a scopo di visualizzazione. Non include token che eseguono l'autenticazione al server durante l'esecuzione di richieste successive, che funziona separatamente usando un cookie oggetto incluso nelle HttpClient richieste al server.

Questa versione dell'articolo illustra l'implementazione di OIDC con il modello Back-end per il front-end (BFF). Modificare il selettore della versione dell'articolo in OIDC senza modello BFF se la specifica dell'app non richiede l'adozione del modello BFF.

La specifica seguente è descritta:

  • L'app Blazor Web usa la modalità di rendering automatico con interattività globale.
  • I servizi provider di stato di autenticazione personalizzati vengono usati dal server e dalle app client per acquisire lo stato di autenticazione dell'utente e fluirlo tra il server e il client.
  • Questa app è un punto di partenza per qualsiasi flusso di autenticazione OIDC. OIDC viene configurato manualmente nell'app e non si basa su Microsoft Entra ID o pacchetti Web MicrosoftIdentity, né l'app di esempio richiede l'hosting di Microsoft Azure. Tuttavia, l'app di esempio può essere usata con Entra, Microsoft Identity Web e ospitata in Azure.
  • Aggiornamento automatico del token non interattivo.
  • Il modello Back-end per front-end (BFF) viene adottato usando .NET Aspira per l'individuazione dei servizi e YARP per il proxy delle richieste a un endpoint di previsione meteo nell'app back-end.
    • Un'API Web back-end cookieusa l'autenticazione con connessione JWT per convalidare i token JWT salvati dall'app Web nell'accesso Blazor .
    • L'aspirare migliora l'esperienza di creazione di app native del cloud .NET. Fornisce un set di strumenti e modelli coerente e con opinioni per la creazione e l'esecuzione di app distribuite.
    • YARP (Yet Another Reverse Proxy) è una libreria usata per creare un server proxy inverso.

Avviso del pacchetto di anteprima

Avviso

Tecnologie e pacchetti usati dall'app BlazorWebAppOidcBff di esempio e descritti in questo articolo sono in versione di anteprima in questo momento. Il contenuto dell'articolo, l'API e l'app di esempio non sono attualmente supportati e non sono attualmente consigliati per l'uso in produzione. L'app di esempio e le indicazioni sono soggette a modifiche senza preavviso.

Prerequisito

.NET Aspire richiede Visual Studio versione 17.10 o successiva.

Esempio di app

L'app di esempio è costituita da cinque progetti:

  • .NET Aspira:
    • Aspire.AppHost: usato per gestire i problemi di orchestrazione di alto livello dell'app.
    • Aspire.ServiceDefaults: contiene configurazioni dell'app .NET Aspire predefinite che possono essere estese e personalizzate in base alle esigenze.
  • MinimalApiJwt: API Web back-end contenente un esempio di endpoint API minimo per i dati meteo.
  • BlazorWebAppOidc: progetto lato server dell'app Blazor Web.
  • BlazorWebAppOidc.Client: progetto lato client dell'app Blazor Web.

Accedere alle app di esempio tramite la cartella della versione più recente dalla radice del repository con il collegamento seguente. I progetti si trovano nella BlazorWebAppOidcBff cartella per .NET 8 o versione successiva.

Visualizzare o scaricare il codice di esempio (procedura per il download)

Progetti .NET Aspire

Per altre informazioni sull'uso di .NET Aspire e sui .AppHost progetti e .ServiceDefaults dell'app di esempio, vedere la documentazione di .NET Aspire.

Verificare di aver soddisfatto i prerequisiti per .NET Aspire. Per altre informazioni, vedere la sezione Prerequisiti di Avvio rapido: Creare la prima app .NET Aspire.

Progetto app Web sul lato Blazor server (BlazorWebAppOidc)

Il BlazorWebAppOidc progetto è il progetto lato server dell'app Blazor Web. Il progetto usa YARP per eseguire il proxy delle richieste a un endpoint delle previsioni meteo nel progetto API Web back-end (MinimalApiJwt) con l'oggetto access_token archiviato nell'autenticazione cookie.

Il BlazorWebAppOidc.http file può essere usato per testare la richiesta di dati meteo. Si noti che il BlazorWebAppOidc progetto deve essere in esecuzione per testare l'endpoint e l'endpoint è hardcoded nel file. Per altre informazioni, vedere Usare file .http in Visual Studio 2022.

Nota

Il progetto server usa IHttpContextAccessor/HttpContext, ma non per i componenti di cui è stato eseguito il rendering interattivo. Per altre informazioni, vedere Linee guida per la mitigazione delle minacce per ASP.NET rendering lato server interattivo CoreBlazor.

Impostazione

Questa sezione illustra come configurare l'app di esempio.

Nota

Per Microsoft Entra ID e Azure AD B2C, è possibile usare microsoft AddMicrosoftIdentityWebAppIdentityWeb (Microsoft.Identity.Web pacchetto NuGet, documentazione dell'API), che aggiunge sia i gestori OIDC Cookie che i gestori di autenticazione con le impostazioni predefinite appropriate. L'app di esempio e le indicazioni contenute in questa sezione non usano Microsoft Identity Web. Le linee guida illustrano come configurare manualmente il gestore OIDC per qualsiasi provider OIDC. Per altre informazioni sull'implementazione di Microsoft Identity Web, vedere le risorse collegate.

La configurazione seguente OpenIdConnectOptions è disponibile nel file del Program progetto nella chiamata a AddOpenIdConnect:

  • SignInScheme: imposta lo schema di autenticazione corrispondente al middleware responsabile della persistenza dell'identità dell'utente dopo un'autenticazione riuscita. Il gestore OIDC deve usare uno schema di accesso in grado di rendere persistenti le credenziali utente tra le richieste. La seguente riga è presente solo a scopo dimostrativo. Se omesso, DefaultSignInScheme viene usato come valore di fallback.

    oidcOptions.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    
  • Ambiti per openid e () (Scopefacoltativo): anche gli openid ambiti e profileprofile sono configurati per impostazione predefinita perché sono necessari per il funzionamento del gestore OIDC, ma potrebbe essere necessario aggiungerli nuovamente se gli ambiti sono inclusi nella Authentication:Schemes:MicrosoftOidc:Scope configurazione. Per indicazioni generali sulla configurazione, vedere Configurazione in ASP.NET Core e configurazione di ASP.NET CoreBlazor.

    oidcOptions.Scope.Add(OpenIdConnectScope.OpenIdProfile);
    
  • SaveTokens: definisce se i token di accesso e aggiornamento devono essere archiviati in AuthenticationProperties dopo un'autorizzazione riuscita. Il valore è impostato su true per autenticare le richieste di dati meteo dal progetto API Web back-end (MinimalApiJwt).

    oidcOptions.SaveTokens = true;
    
  • Ambito per l'accesso offline (Scope): l'ambito offline_access è obbligatorio per il token di aggiornamento.

    oidcOptions.Scope.Add(OpenIdConnectScope.OfflineAccess);
    
  • Ambiti per ottenere i dati meteo dall'API Web (Scope): l'ambito Weather.Get è configurato nel portale di Azure o Entra in Esporre un'API. Questa operazione è necessaria per il progetto API Web back-end (MinimalApiJwt) per convalidare il token di accesso con bearer JWT.

    oidcOptions.Scope.Add("{APP ID URI}/{API NAME}");
    

    Esempio:

    • URI ID app ({APP ID URI}): https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID}
      • Nome directory ({DIRECTORY NAME}): contoso
      • ID applicazione (client) ({CLIENT ID}): 4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f
    • Ambito configurato per i dati meteo da MinimalApiJwt ({API NAME}): Weather.Get
    oidcOptions.Scope.Add("https://contoso.onmicrosoft.com/4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f/Weather.Get");
    

    L'esempio precedente riguarda un'app registrata in un tenant con un tipo di tenant AAD B2C. Se l'app viene registrata in un tenant ME-ID, l'URI ID app è diverso, quindi l'ambito è diverso.

    Esempio:

    • URI ID app ({APP ID URI}): api://{CLIENT ID} con ID applicazione (client) ({CLIENT ID}): 4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f
    • Ambito configurato per i dati meteo da MinimalApiJwt ({API NAME}): Weather.Get
    oidcOptions.Scope.Add("api://4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f/Weather.Get");
    
  • Authority e ClientId: imposta l'autorità e l'ID client per le chiamate OIDC.

    oidcOptions.Authority = "{AUTHORITY}";
    oidcOptions.ClientId = "{CLIENT ID}";
    

    Esempio:

    • Autorità (): https://login.microsoftonline.com/a3942615-d115-4eb7-bc84-9974abcf5064/v2.0/ ({AUTHORITY}usa l'ID a3942615-d115-4eb7-bc84-9974abcf5064tenant )
    • ID client ({CLIENT ID}): 4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f
    oidcOptions.Authority = "https://login.microsoftonline.com/a3942615-d115-4eb7-bc84-9974abcf5064/v2.0/";
    oidcOptions.ClientId = "4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f";
    

    Esempio per l'autorità "common" di Microsoft Azure:

    L'autorità "comune" deve essere usata per le app multi-tenant. È anche possibile usare l'autorità "comune" per le app a tenant singolo, ma è necessario un personalizzato IssuerValidator , come illustrato più avanti in questa sezione.

    oidcOptions.Authority = "https://login.microsoftonline.com/common/v2.0/";
    
  • ClientSecret: segreto client OIDC.

    L'esempio seguente è solo a scopo di test e dimostrazione. Non archiviare il segreto client nell'assembly dell'app o controllare il segreto nel controllo del codice sorgente. Archiviare il segreto client in Segreti utente, Azure Key Vault o una variabile di ambiente.

    La configurazione dello schema di autenticazione viene letta automaticamente da builder.Configuration["Authentication:Schemes:{SCHEME NAME}:{PropertyName}"], dove il {SCHEME NAME} segnaposto è lo schema, ovvero per MicrosoftOidc impostazione predefinita. Poiché la configurazione è preconfigurata, un segreto client può essere letto automaticamente tramite la Authentication:Schemes:MicrosoftOidc:ClientSecret chiave di configurazione. Nel server che usa variabili di ambiente assegnare alla variabile Authentication__Schemes__MicrosoftOidc__ClientSecretdi ambiente il nome :

    set Authentication__Schemes__MicrosoftOidc__ClientSecret={CLIENT SECRET}
    

    Solo per la dimostrazione e il test, ClientSecret è possibile impostare direttamente . Non impostare il valore direttamente per le app di produzione distribuite. Per una sicurezza leggermente migliorata, compilare in modo condizionale la riga con il DEBUG simbolo :

    #if DEBUG
    oidcOptions.ClientSecret = "{CLIENT SECRET}";
    #endif
    

    Esempio:

    Segreto client (): 463471c8c4...f90d674bc9 ({CLIENT SECRET}abbreviato per la visualizzazione)

    #if DEBUG
    oidcOptions.ClientSecret = "463471c8c4...137f90d674bc9";
    #endif
    
  • ResponseType: configura il gestore OIDC per eseguire solo il flusso del codice di autorizzazione. Le concessioni implicite e i flussi ibridi non sono necessari in questa modalità.

    Nella configurazione di registrazione dell'app Entra o portale di Azure implicita e dei flussi ibridi, non selezionare la casella di controllo per l'endpoint di autorizzazione per restituire token di accesso o token ID. Il gestore OIDC richiede automaticamente i token appropriati usando il codice restituito dall'endpoint di autorizzazione.

    oidcOptions.ResponseType = OpenIdConnectResponseType.Code;
    
  • MapInboundClaimse la configurazione di NameClaimType e : molti server OIDC usano "name" e "role" anziché le impostazioni predefinite SOAP/WS-Fed in ClaimTypesRoleClaimType. Quando MapInboundClaims è impostato su false, il gestore non esegue mapping delle attestazioni e i nomi delle attestazioni del token JWT vengono usati direttamente dall'app. L'esempio seguente esegue manualmente il mapping del nome e delle attestazioni del ruolo:

Nota

MapInboundClaims deve essere impostato su false per la maggior parte dei provider OIDC, che impedisce la ridenominazione delle attestazioni.

oidcOptions.MapInboundClaims = false;
oidcOptions.TokenValidationParameters.NameClaimType = JwtRegisteredClaimNames.Name;
oidcOptions.TokenValidationParameters.RoleClaimType = "role";
  • Configurazione del percorso: i percorsi devono corrispondere all'URI di reindirizzamento (percorso di callback di accesso) e ai percorsi di reindirizzamento post disconnessione (percorso di callback con disconnessione) configurati durante la registrazione dell'applicazione con il provider OIDC. Nel portale di Azure i percorsi vengono configurati nel pannello Autenticazione della registrazione dell'app. Entrambi i percorsi di accesso e disconnessione devono essere registrati come URI di reindirizzamento. I valori predefiniti sono /signin-oidc e /signout-callback-oidc.

    • CallbackPath: percorso della richiesta all'interno del percorso di base dell'app in cui viene restituito l'agente utente.

      In Entra o portale di Azure impostare il percorso nell'URI di reindirizzamento della configurazione della piattaforma Web:

      https://localhost/signin-oidc

      Nota

      Una porta non è necessaria per localhost gli indirizzi.

    • SignedOutCallbackPath: percorso della richiesta all'interno del percorso di base dell'app in cui viene restituito l'agente utente dopo la disconnessione dal provider di identità.

      In Entra o portale di Azure impostare il percorso nell'URI di reindirizzamento della configurazione della piattaforma Web:

      https://localhost/signout-callback-oidc

      Nota

      Una porta non è necessaria per localhost gli indirizzi.

      Nota

      Se si usa Microsoft Identity Web, il provider attualmente reindirizza di nuovo a SignedOutCallbackPath se viene usata l'autorità microsoftonline.com (https://login.microsoftonline.com/{TENANT ID}/v2.0/). Questa limitazione non esiste se è possibile usare l'autorità "comune" con Microsoft Identity Web. Per altre informazioni, vedere postLogoutRedirectUri not working when authority URL contains a tenant ID (AzureAD/microsoft-authentication-library-for-js #5783).

    • RemoteSignOutPath: le richieste ricevute in questo percorso causano il richiamo della disconnessione da parte del gestore tramite lo schema di disconnessione.

      In Entra o portale di Azure impostare l'URL di disconnessione del canale anteriore:

      https://localhost/signout-oidc

      Nota

      Una porta non è necessaria per localhost gli indirizzi.

    oidcOptions.CallbackPath = new PathString("{PATH}");
    oidcOptions.SignedOutCallbackPath = new PathString("{PATH}");
    oidcOptions.RemoteSignOutPath = new PathString("{PATH}");
    

    Esempi (valori predefiniti):

    oidcOptions.CallbackPath = new PathString("/signin-oidc");
    oidcOptions.SignedOutCallbackPath = new PathString("/signout-callback-oidc");
    oidcOptions.RemoteSignOutPath = new PathString("/signout-oidc");
    
  • (Microsoft Azure solo con l'endpoint "comune") TokenValidationParameters.IssuerValidator: molti provider OIDC funzionano con il validator predefinito dell'autorità di certificazione, ma è necessario tenere conto dell'autorità di certificazione con parametri con l'ID tenant ({TENANT ID}) restituito da https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration. Per altre informazioni, vedere SecurityTokenInvalidIssuerException con OpenID Connessione e l'endpoint "common" di Azure AD (AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet #1731)..

    Solo per le app che usano Microsoft Entra ID o Azure AD B2C con l'endpoint "comune":

    var microsoftIssuerValidator = AadIssuerValidator.GetAadIssuerValidator(oidcOptions.Authority);
    oidcOptions.TokenValidationParameters.IssuerValidator = microsoftIssuerValidator.Validate;
    

Codice dell'app di esempio

Esaminare l'app di esempio per le funzionalità seguenti:

  • Aggiornamento automatico del token non interattivo con l'aiuto di un aggiornamento personalizzato cookie (CookieOidcRefresher.cs).
  • La PersistingAuthenticationStateProvider classe (PersistingAuthenticationStateProvider.cs) è un lato AuthenticationStateProvider server che usa PersistentComponentState per trasferire lo stato di autenticazione al client, che viene quindi risolto per la durata dell'applicazione WebAssembly.
  • Le richieste all'app Blazor Web vengono inoltrate tramite proxy al progetto API Web back-end (MinimalApiJwt). MapForwarder nel file aggiunge l'inoltro Program diretto di richieste HTTP che corrispondono al modello specificato a una destinazione specifica usando la configurazione predefinita per la richiesta in uscita, le trasformazioni personalizzate e il client HTTP predefinito:
    • Quando si esegue il rendering del Weather componente nel server, il componente usa ServerWeatherForecaster per proxyare la richiesta di dati meteo con il token di accesso dell'utente.
    • Quando viene eseguito il rendering del componente nel client, il componente usa l'implementazione del ClientWeatherForecaster servizio, che usa un preconfigurato HttpClient (nel file del Program progetto client) per effettuare una chiamata API Web al progetto server. Un endpoint API minimo (/weather-forecast) definito nel file del Program progetto server trasforma la richiesta con il token di accesso dell'utente per ottenere i dati meteo.

Per altre informazioni sulle chiamate API (Web) tramite astrazioni di servizio in Blazor App Web, vedere Chiamare un'API Web da un'app ASP.NET CoreBlazor.

Progetto app Web sul lato Blazor client (BlazorWebAppOidc.Client)

Il BlazorWebAppOidc.Client progetto è il progetto lato client dell'app Blazor Web.

La PersistentAuthenticationStateProvider classe (PersistentAuthenticationStateProvider.cs) è un lato AuthenticationStateProvider client che determina lo stato di autenticazione dell'utente cercando i dati persistenti nella pagina quando è stato eseguito il rendering nel server. Lo stato di autenticazione è fisso per la durata dell'applicazione WebAssembly.

Se l'utente deve accedere o disconnettersi, è necessario ricaricare una pagina completa.

L'app di esempio fornisce solo un nome utente e un messaggio di posta elettronica a scopo di visualizzazione. Non include token che eseguono l'autenticazione al server durante l'esecuzione di richieste successive, che funziona separatamente usando un cookie oggetto incluso nelle HttpClient richieste al server.

Progetto API Web back-end (MinimalApiJwt)

Il MinimalApiJwt progetto è un'API Web back-end per più progetti front-end. Il progetto configura un endpoint API minimo per i dati meteo. Le richieste dal progetto sul lato server dell'app Blazor Web (BlazorWebAppOidc) vengono inviate tramite proxy al MinimalApiJwt progetto.

Impostazione

Configurare il progetto nella JwtBearerOptions classe della AddJwtBearer chiamata nel file del Program progetto:

  • Audience: imposta il gruppo di destinatari per qualsiasi token di Connessione OpenID ricevuto.

    Nel portale di Azure o Entra: associare il valore solo al percorso dell'URI ID applicazione configurato quando si aggiunge l'ambito Weather.Get in Esporre un'API:

    jwtOptions.Audience = "{APP ID URI}";
    

    Esempio:

    URI ID app ({APP ID URI}): https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID}:

    • Nome directory ({DIRECTORY NAME}): contoso
    • ID applicazione (client) ({CLIENT ID}): 4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f
    jwtOptions.Audience = "https://contoso.onmicrosoft.com/4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f";
    

    L'esempio precedente riguarda un'app registrata in un tenant con un tipo di tenant AAD B2C. Se l'app viene registrata in un tenant ME-ID, l'URI ID app è diverso, quindi il gruppo di destinatari è diverso.

    Esempio:

    URI ID app ({APP ID URI}): api://{CLIENT ID} con ID applicazione (client) ({CLIENT ID}): 4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f

    jwtOptions.Audience = "api://4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f";
    
  • Authority: imposta l'autorità per l'esecuzione di chiamate openID Connessione. Trovare la corrispondenza del valore con l'autorità configurata per il gestore OIDC in BlazorWebAppOidc/Program.cs:

    jwtOptions.Authority = "{AUTHORITY}";
    

    Esempio:

    Autorità (): https://login.microsoftonline.com/a3942615-d115-4eb7-bc84-9974abcf5064/v2.0/ ({AUTHORITY}usa l'ID a3942615-d115-4eb7-bc84-9974abcf5064tenant )

    jwtOptions.Authority = "https://login.microsoftonline.com/a3942615-d115-4eb7-bc84-9974abcf5064/v2.0/";
    

    L'esempio precedente riguarda un'app registrata in un tenant con un tipo di tenant AAD B2C. Se l'app è registrata in un tenant ME-ID, l'autorità deve corrispondere all'issurer (iss) del token JWT restituito dal provider di identità:

    jwtOptions.Authority = "https://sts.windows.net/a3942615-d115-4eb7-bc84-9974abcf5064/";
    

API minima per i dati meteo

Proteggere l'endpoint dei dati delle previsioni meteo nel file del Program progetto:

app.MapGet("/weather-forecast", () =>
{
    var forecast = 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();
    return forecast;
}).RequireAuthorization();

Il RequireAuthorization metodo di estensione richiede l'autorizzazione per la definizione di route. Per tutti i controller aggiunti al progetto, aggiungere l'attributo [Authorize] al controller o all'azione.

Reindirizzamento alla home page all'accesso

Quando un utente si sposta all'interno dell'app, il LogInOrOut componente (Layout/LogInOrOut.razor) imposta un campo nascosto per l'URL restituito (ReturnUrl) sul valore dell'URL corrente (currentURL). Quando l'utente si disconnette dall'app, il provider di identità li restituisce alla pagina da cui si è disconnesso.

Se l'utente si disconnette da una pagina sicura, viene restituito alla stessa pagina protetta dopo la disconnessione solo per essere restituito tramite il processo di autenticazione. Questo comportamento è corretto quando gli utenti devono cambiare account di frequente. Tuttavia, una specifica di app alternativa può richiedere che l'utente venga restituito alla home page dell'app o ad altre pagine dopo la disconnettersi. L'esempio seguente illustra come impostare la home page dell'app come URL restituito per le operazioni di disconnessione.

Le modifiche importanti apportate al LogInOrOut componente sono illustrate nell'esempio seguente. L'oggetto value del campo nascosto per è ReturnUrl impostato sulla home page in /. IDisposable non è più implementato. l'oggetto NavigationManager non viene più inserito. L'intero @code blocco viene rimosso.

Layout/LogInOrOut.razor:

@using Microsoft.AspNetCore.Authorization

<div class="nav-item px-3">
    <AuthorizeView>
        <Authorized>
            <form action="authentication/logout" method="post">
                <AntiforgeryToken />
                <input type="hidden" name="ReturnUrl" value="/" />
                <button type="submit" class="nav-link">
                    <span class="bi bi-arrow-bar-left-nav-menu" aria-hidden="true">
                    </span> Logout @context.User.Identity?.Name
                </button>
            </form>
        </Authorized>
        <NotAuthorized>
            <a class="nav-link" href="authentication/login">
                <span class="bi bi-person-badge-nav-menu" aria-hidden="true"></span> 
                Login
            </a>
        </NotAuthorized>
    </AuthorizeView>
</div>

Nonce crittografico

Un nonce è un valore stringa che associa la sessione di un client a un token ID per attenuare gli attacchi di riproduzione.

Se si riceve un errore nonce durante lo sviluppo e il test dell'autenticazione, usare una nuova sessione del browser InPrivate/incognito per ogni esecuzione di test, indipendentemente dalla piccola modifica apportata all'app o dall'utente di test perché i dati non aggiornati cookie possono causare un errore nonce. Per altre informazioni, vedere la sezione s e i dati del Cookiesito.

Un nonce non è obbligatorio o viene usato quando un token di aggiornamento viene scambiato per un nuovo token di accesso. Nell'app di esempio , (CookieOidcRefresherCookieOidcRefresher.cs) imposta OpenIdConnectProtocolValidator.RequireNonce deliberatamente su false.

Risoluzione dei problemi

Registrazione

L'app server è un'app standard ASP.NET Core. Vedere le linee guida per la registrazione di ASP.NET Core per abilitare un livello di registrazione inferiore nell'app server.

Per abilitare la registrazione di debug o traccia per Blazor WebAssembly l'autenticazione, vedere la sezione Registrazione dell'autenticazione lato client di ASP.NET Core Blazor con il selettore della versione dell'articolo impostato su ASP.NET Core 7.0 o versione successiva.

Errori comuni

  • Configurazione errata dell'app o Identity del provider (IP)

    Gli errori più comuni sono causati da una configurazione errata. Di seguito sono riportati alcuni esempi:

    • A seconda dei requisiti dello scenario, un'autorità mancante o non corretta, istanza, ID tenant, dominio tenant, ID client o URI di reindirizzamento impedisce a un'app di autenticare i client.
    • Gli ambiti di richiesta non corretti impediscono ai client di accedere agli endpoint DELL'API Web del server.
    • Autorizzazioni DELL'API server non corrette o mancanti impediscono ai client di accedere agli endpoint DELL'API Web del server.
    • L'esecuzione dell'app in una porta diversa da quella configurata nell'URI di reindirizzamento della registrazione dell'app ip. Si noti che non è necessaria una porta per Microsoft Entra ID e un'app in esecuzione in un localhost indirizzo di test di sviluppo, ma la configurazione della porta dell'app e la porta in cui è in esecuzione l'app devono corrispondere per gli indirizzi nonlocalhost .

    La copertura della configurazione in questo articolo illustra esempi della configurazione corretta. Controllare attentamente la configurazione alla ricerca di errori di configurazione di app e IP.

    Se la configurazione è corretta:

    • Analizzare i log delle applicazioni.

    • Esaminare il traffico di rete tra l'app client e l'app IP o server con gli strumenti di sviluppo del browser. Spesso, un messaggio di errore esatto o un messaggio con un indizio sulla causa del problema viene restituito al client dall'app IP o server dopo aver effettuato una richiesta. Strumenti di sviluppo materiale sussidiario sono disponibili negli articoli seguenti:

    Il team della documentazione risponde al feedback e ai bug dei documenti negli articoli (aprire un problema dalla sezione Commenti e suggerimenti della pagina ), ma non è in grado di fornire supporto tecnico. Sono disponibili diversi forum di supporto pubblico per facilitare la risoluzione dei problemi di un'app. Consigliamo quanto segue:

    I forum precedenti non sono di proprietà o controllati da Microsoft.

    Per i report sui bug del framework non riservati, non sensibili e non riservati, aprire un problema con l'unità del prodotto ASP.NET Core. Non aprire un problema con l'unità di prodotto fino a quando non hai approfondito la causa di un problema e non puoi risolverlo autonomamente e con l'aiuto della community in un forum di supporto pubblico. L'unità prodotto non è in grado di risolvere i problemi relativi alle singole app interrotte a causa di semplici errori di configurazione o casi d'uso che coinvolgono servizi di terze parti. Se un report è sensibile o riservato in natura o descrive un potenziale difetto di sicurezza nel prodotto che gli utenti malintenzionati possono sfruttare, vedere Segnalazione di problemi di sicurezza e bug (dotnet/aspnetcorerepository GitHub).

  • Client non autorizzato per ME-ID

    info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2] Autorizzazione non riuscita. Questi requisiti non sono stati soddisfatti: DenyAnonymousAuthorizationRequirement: richiede un utente autenticato.

    Errore di callback di accesso da ME-ID:

    • Errore: unauthorized_client
    • Description (Descrizione): AADB2C90058: The provided application is not configured to allow public clients.

    Per risolvere l'errore:

    1. Nella portale di Azure accedere al manifesto dell'app.
    2. Impostare l'attributo allowPublicClient su null o .true

Cookies e i dati del sito

Cookies e i dati del sito possono persistere tra gli aggiornamenti delle app e interferire con i test e la risoluzione dei problemi. Cancellare quanto segue quando si apportano modifiche al codice dell'app, modifiche all'account utente con il provider o modifiche alla configurazione dell'app del provider:

  • Account di accesso cookieutente
  • App cookies
  • Dati del sito memorizzati nella cache e archiviati

Un approccio per evitare che i dati del sito e di s persistenti cookieinterferiscano con i test e la risoluzione dei problemi consiste nel:

  • Configurare un browser
    • Usare un browser per i test che è possibile configurare per eliminare tutti i cookie dati del sito e ogni volta che il browser viene chiuso.
    • Assicurarsi che il browser venga chiuso manualmente o dall'IDE per qualsiasi modifica apportata alla configurazione dell'app, dell'utente di test o del provider.
  • Usare un comando personalizzato per aprire un browser in modalità InPrivate o In incognito in Visual Studio:
    • Aprire la finestra di dialogo Sfoglia con dal pulsante Esegui di Visual Studio.
    • Seleziona il pulsante Aggiungi.
    • Specificare il percorso del browser nel campo Programma . I percorsi eseguibili seguenti sono percorsi di installazione tipici per Windows 10. Se il browser è installato in un percorso diverso o non si usa Windows 10, specificare il percorso dell'eseguibile del browser.
      • Microsoft Edge: C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe
      • Google Chrome: C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
      • Mozilla Firefox: C:\Program Files\Mozilla Firefox\firefox.exe
    • Nel campo Argomenti specificare l'opzione della riga di comando usata dal browser per aprire in modalità InPrivate o Incognito. Alcuni browser richiedono l'URL dell'app.
      • Microsoft Edge: usare -inprivate.
      • Google Chrome: usare --incognito --new-window {URL}, dove il segnaposto {URL} è l'URL da aprire (ad esempio, https://localhost:5001).
      • Mozilla Firefox: usare -private -url {URL}, dove il segnaposto {URL} è l'URL da aprire (ad esempio, https://localhost:5001).
    • Specificare un nome nel campo Nome descrittivo. Ad esempio: Firefox Auth Testing.
    • Selezionare il pulsante OK.
    • Per evitare di dover selezionare il profilo del browser per ogni iterazione di test con un'app, impostare il profilo come predefinito con il pulsante Imposta come predefinito .
    • Assicurarsi che il browser sia chiuso dall'IDE per qualsiasi modifica apportata all'app, all'utente di test o alla configurazione del provider.

Aggiornamenti di app

Un'app funzionante potrebbe non riuscire immediatamente dopo l'aggiornamento di .NET Core SDK nel computer di sviluppo o la modifica delle versioni dei pacchetti all'interno dell'app. In alcuni casi i pacchetti incoerenti possono interrompere un'app quando si eseguono aggiornamenti principali. La maggior parte di questi problemi può essere risolta attenendosi alle istruzioni seguenti:

  1. Cancellare le cache dei pacchetti NuGet del sistema locale eseguendo dotnet nuget locals all --clear da una shell dei comandi.
  2. Eliminare le cartelle e obj del bin progetto.
  3. Ripristinare e ricompilare il progetto.
  4. Eliminare tutti i file nella cartella di distribuzione nel server prima di ridistribuire l'app.

Nota

L'uso di versioni del pacchetto incompatibili con il framework di destinazione dell'app non è supportato. Per informazioni su un pacchetto, usare La raccolta NuGet o Esplora pacchetti FuGet.

Eseguire l'app server

Durante il test e la risoluzione dei problemi dell'app Blazor Web, assicurarsi di eseguire l'app dal progetto server.

Esaminare l'utente

Il componente seguente UserClaims può essere usato direttamente nelle app o funge da base per un'ulteriore personalizzazione.

UserClaims.razor:

@page "/user-claims"
@using System.Security.Claims
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]

<PageTitle>User Claims</PageTitle>

<h1>User Claims</h1>

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

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

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

    protected override async Task OnInitializedAsync()
    {
        if (AuthState == null)
        {
            return;
        }

        var authState = await AuthState;
        claims = authState.User.Claims;
    }
}

Risorse aggiuntive