From 4c5d95bd1e7920f9f7cd0b3c6dc7cb2e0a8bcbb8 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Fri, 16 Sep 2022 06:20:47 -0500 Subject: [PATCH] Auth State Provider registration change --- aspnetcore/blazor/hybrid/security/index.md | 531 ++++++++++++++++++ aspnetcore/blazor/security/server/index.md | 161 +++++- .../webassembly/additional-scenarios.md | 4 +- 3 files changed, 692 insertions(+), 4 deletions(-) diff --git a/aspnetcore/blazor/hybrid/security/index.md b/aspnetcore/blazor/hybrid/security/index.md index a57e9301a44b..c234617ba02a 100644 --- a/aspnetcore/blazor/hybrid/security/index.md +++ b/aspnetcore/blazor/hybrid/security/index.md @@ -13,6 +13,8 @@ zone_pivot_groups: blazor-hybrid-frameworks This article describes ASP.NET Core's support for the configuration and management of security and ASP.NET Core Identity in Blazor Hybrid apps. +::: moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" + Authentication in Blazor Hybrid apps is handled by native platform libraries, as they offer enhanced security guarantees that the browser sandbox can't offer. Authentication of native apps uses an OS-specific mechanism or via a federated protocol, such as [OpenID Connect (OIDC)](https://openid.net/connect/). Follow the guidance for the identity provider that you've selected for the app and then further integrate identity with Blazor using the guidance in this article. Integrating authentication must achieve the following goals for Razor components and services: @@ -535,3 +537,532 @@ When implementing authentication: * * + +::: moniker-end + +::: moniker range=">= aspnetcore-7.0" + +Authentication in Blazor Hybrid apps is handled by native platform libraries, as they offer enhanced security guarantees that the browser sandbox can't offer. Authentication of native apps uses an OS-specific mechanism or via a federated protocol, such as [OpenID Connect (OIDC)](https://openid.net/connect/). Follow the guidance for the identity provider that you've selected for the app and then further integrate identity with Blazor using the guidance in this article. + +Integrating authentication must achieve the following goals for Razor components and services: + +* Use the abstractions in the [`Microsoft.AspNetCore.Components.Authorization`](https://www.nuget.org/packages/Microsoft.AspNetCore.Components.Authorization) package, such as . +* React to changes in the authentication context. +* Access credentials provisioned by the app from the identity provider, such as access tokens to perform authorized API calls. + +After authentication is added to a .NET MAUI, WPF, or Windows Forms app and users are able to log in and log out successfully, integrate authentication with Blazor to make the authenticated user available to Razor components and services. Perform the following steps: + +* Reference the [`Microsoft.AspNetCore.Components.Authorization`](https://www.nuget.org/packages/Microsoft.AspNetCore.Components.Authorization) package. + + [!INCLUDE[](~/includes/package-reference.md)] + +* Implement a custom , which is the abstraction that Razor components use to access information about the authenticated user and to receive updates when the authentication state changes. +* Register the custom authentication state provider in the dependency injection container. + +:::zone pivot="maui" + +.NET MAUI apps use [Xamarin.Essentials: Web Authenticator](/xamarin/essentials/web-authenticator): The `WebAuthenticator` class allows the app to initiate browser-based authentication flows that listen for a callback to a specific URL registered with the app. + +:::zone-end + +:::zone pivot="wpf" + +WPF apps use the [Microsoft identity platform](/azure/active-directory/develop/) to integrate with Azure Active Directory (AAD) and AAD B2C. For guidance and examples, see the following resources: + +* [Overview of the Microsoft Authentication Library (MSAL)](/azure/active-directory/develop/msal-overview) +* [Sign-in a user with the Microsoft Identity Platform in a WPF Desktop application and call an ASP.NET Core Web API](/samples/azure-samples/active-directory-dotnet-native-aspnetcore-v2/1-desktop-app-calls-web-api/) +* [Add authentication to your Windows (WPF) app](/azure/developer/mobile-apps/azure-mobile-apps/quickstarts/wpf/authentication) +* [Tutorial: Sign in users and call Microsoft Graph in Windows Presentation Foundation (WPF) desktop app](/azure/active-directory/develop/tutorial-v2-windows-desktop) +* [Quickstart: Acquire a token and call Microsoft Graph API from a desktop application](/azure/active-directory/develop/desktop-app-quickstart?pivots=devlang-windows-desktop) +* [Quickstart: Set up sign in for a desktop app using Azure Active Directory B2C](/azure/active-directory-b2c/quickstart-native-app-desktop) +* [Configure authentication in a sample WPF desktop app by using Azure AD B2C](/azure/active-directory-b2c/configure-authentication-sample-wpf-desktop-app) + +:::zone-end + +:::zone pivot="winforms" + +Windows Forms apps use the [Microsoft identity platform](/azure/active-directory/develop/) to integrate with Azure Active Directory (AAD) and AAD B2C. For more information, see [Overview of the Microsoft Authentication Library (MSAL)](/azure/active-directory/develop/msal-overview). + +:::zone-end + +## Create a custom `AuthenticationStateProvider` without user change updates + +If the app authenticates the user immediately after the app launches and the authenticated user remains the same for the entirety of the app lifetime, user change notifications aren't required, and the app only provides information about the authenticated user. In this scenario, the user logs into the app when the app is opened, and the app displays the login screen again after the user logs out. The following `ExternalAuthStateProvider` is an example implementation of a custom for this authentication scenario. + +> [!NOTE] +> The following custom doesn't declare a namespace in order to make the code example applicable to any Blazor Hybrid app. However, a best practice is to provide your app's namespace when you implement the example in a production app. + +`ExternalAuthStateProvider.cs`: + +```csharp +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components.Authorization; + +public class ExternalAuthStateProvider : AuthenticationStateProvider +{ + private readonly Task authenticationState; + + public ExternalAuthStateProvider(AuthenticatedUser user) => + authenticationState = Task.FromResult(new AuthenticationState(user.Principal)); + + public override Task GetAuthenticationStateAsync() => + authenticationState; +} + +public class AuthenticatedUser +{ + public ClaimsPrincipal Principal { get; set; } = new(); +} +``` + +:::zone pivot="maui" + +The following steps describe how to: + +* Add required namespaces. +* Add the authorization services and Blazor abstractions to the service collection. +* Build the service collection. +* Resolve the `AuthenticatedUser` service to set the authenticated user's claims principal. See your identity provider's documentation for details. +* Return the built host. + +In the `MauiProgram.CreateMauiApp` method of `MainWindow.cs`, add namespaces for and : + +```csharp +using Microsoft.AspNetCore.Components.Authorization; +using System.Security.Claims; +``` + +Remove the following line of code that returns a built `Microsoft.Maui.Hosting.MauiApp`: + +```diff +- return builder.Build(); +``` + +Replace the preceding line of code with the following code. Add OpenID/MSAL code to authenticate the user. See your identity provider's documentation for details. + +```csharp +builder.Services.AddAuthorizationCore(); +builder.Services.TryAddScoped(); +builder.Services.AddSingleton(); +var host = builder.Build(); + +var authenticatedUser = host.Services.GetRequiredService(); + +/* +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; +``` + +:::zone-end + +:::zone pivot="wpf" + +The following steps describe how to: + +* Add required namespaces. +* Add the authorization services and Blazor abstractions to the service collection. +* Build the service collection and add the built service collection as a resource to the app's `ResourceDictionary`. +* Resolve the `AuthenticatedUser` service to set the authenticated user's claims principal. See your identity provider's documentation for details. +* Return the built host. + +In the `MainWindow`'s constructor (`MainWindow.xaml.cs`), add namespaces for and : + +```csharp +using Microsoft.AspNetCore.Components.Authorization; +using System.Security.Claims; +``` + +Remove the following line of code that adds the built service collection as a resource to the app's `ResourceDictionary`: + +```diff +- Resources.Add("services", serviceCollection.BuildServiceProvider()); +``` + +Replace the preceding line of code with the following code. Add OpenID/MSAL code to authenticate the user. See your identity provider's documentation for details. + +```csharp +serviceCollection.AddAuthorizationCore(); +serviceCollection.TryAddScoped(); +serviceCollection.AddSingleton(); +var services = serviceCollection.BuildServiceProvider(); +Resources.Add("services", services); + +var authenticatedUser = services.GetRequiredService(); + +/* +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; +``` + +:::zone-end + +:::zone pivot="winforms" + +The following steps describe how to: + +* Add required namespaces. +* Add the authorization services and Blazor abstractions to the service collection. +* Build the service collection and add the built service collection to the app's service provider. +* Resolve the `AuthenticatedUser` service to set the authenticated user's claims principal. See your identity provider's documentation for details. + +In the `Form1`'s constructor (`Form1.cs`), add namespaces for and : + +```csharp +using Microsoft.AspNetCore.Components.Authorization; +using System.Security.Claims; +``` + +Remove the following line of code that sets the built service collection to the app's service provider: + +```diff +- blazorWebView1.Services = services.BuildServiceProvider(); +``` + +Replace the preceding line of code with the following code. Add OpenID/MSAL code to authenticate the user. See your identity provider's documentation for details. + +```csharp +services.AddAuthorizationCore(); +services.TryAddScoped(); +services.AddSingleton(); +var serviceCollection = services.BuildServiceProvider(); +blazorWebView1.Services = serviceCollection; + +var authenticatedUser = serviceCollection.GetRequiredService(); + +/* +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; +``` + +:::zone-end + +## Create a custom `AuthenticationStateProvider` with user change updates + +To update the user while the Blazor app is running, call within the implementation using ***either*** of the following approaches: + +* [Signal an authentication update from outside of the `BlazorWebView`](#signal-an-authentication-update-from-outside-of-the-blazorwebview-option-1)) +* [Handle authentication within the `BlazorWebView`](#handle-authentication-within-the-blazorwebview-option-2) + +### Signal an authentication update from outside of the `BlazorWebView` (Option 1) + +A custom can use a global service to signal an authentication update. We recommend that the service offer an event that the can subscribe to, where the event invokes . + +> [!NOTE] +> The following custom doesn't declare a namespace in order to make the code example applicable to any Blazor Hybrid app. However, a best practice is to provide your app's namespace when you implement the example in a production app. + +`ExternalAuthStateProvider.cs`: + +```csharp +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 GetAuthenticationStateAsync() => + Task.FromResult(currentUser); +} + +public class ExternalAuthService +{ + public event Action? UserChanged; + private ClaimsPrincipal? currentUser; + + public ClaimsPrincipal CurrentUser + { + get { return currentUser ?? new(); } + set + { + currentUser = value; + + if (UserChanged is not null) + { + UserChanged(currentUser); + } + } + } +} +``` + +:::zone pivot="maui" + +In the `MauiProgram.CreateMauiApp` method of `MainWindow.cs`, add a namespace for : + +```csharp +using Microsoft.AspNetCore.Components.Authorization; +``` + +Add the authorization services and Blazor abstractions to the service collection: + +```csharp +builder.Services.AddAuthorizationCore(); +builder.Services.TryAddScoped(); +builder.Services.AddSingleton(); +``` + +:::zone-end + +:::zone pivot="wpf" + +In the `MainWindow`'s constructor (`MainWindow.xaml.cs`), add a namespace for : + +```csharp +using Microsoft.AspNetCore.Components.Authorization; +``` + +Add the authorization services and the Blazor abstractions to the service collection: + +```csharp +serviceCollection.AddAuthorizationCore(); +serviceCollection.TryAddScoped(); +serviceCollection.AddSingleton(); +``` + +:::zone-end + +:::zone pivot="winforms" + +In the `Form1`'s constructor (`Form1.cs`), add a namespace for : + +```csharp +using Microsoft.AspNetCore.Components.Authorization; +``` + +Add the authorization services and Blazor abstractions to the service collection: + +```csharp +services.AddAuthorizationCore(); +services.TryAddScoped(); +services.AddSingleton(); +``` + +:::zone-end + +Wherever the app authenticates a user, resolve the `ExternalAuthService` service: + +```csharp +var authService = host.Services.GetRequiredService(); +``` + +Execute your custom OpenID/MSAL code to authenticate the user. See your identity provider's documentation for details. The authenticated user (`authenticatedUser` in the following example) is a new based on a new . + +Set the current user to the authenticated user: + +```csharp +authService.CurrentUser = authenticatedUser; +``` + +An alternative to the preceding approach is to set the user's principal on instead of setting it via a service, which avoids use of the dependency injection container: + +```csharp +public class CurrentThreadUserAuthenticationStateProvider : AuthenticationStateProvider +{ + public override Task GetAuthenticationStateAsync() => + Task.FromResult( + new AuthenticationState(Thread.CurrentPrincipal as ClaimsPrincipal ?? + new ClaimsPrincipal(new ClaimsIdentity()))); +} +``` + +Using the alternative approach, only authorization services () and `CurrentThreadUserAuthenticationStateProvider` (`.TryAddScoped()`) are added to the service collection. + +### Handle authentication within the `BlazorWebView` (Option 2) + +A custom can include additional methods to trigger log in and log out and update the user. + +> [!NOTE] +> The following custom doesn't declare a namespace in order to make the code example applicable to any Blazor Hybrid app. However, a best practice is to provide your app's namespace when you implement the example in a production app. + +`ExternalAuthStateProvider.cs`: + +```csharp +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 GetAuthenticationStateAsync() => + Task.FromResult(new AuthenticationState(currentUser)); + + public Task LogInAsync() + { + var loginTask = LogInAsyncCore(); + NotifyAuthenticationStateChanged(loginTask); + + return loginTask; + + async Task LogInAsyncCore() + { + var user = await LoginWithExternalProviderAsync(); + currentUser = user; + + return new AuthenticationState(currentUser); + } + } + + private Task 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))); + } +} +``` + +In the preceding example: + +* The call to `LogInAsyncCore` triggers the login process. +* The call to notifies that an update is in progress, which allows the app to provide a temporary UI during the login or logout process. +* Returning `loginTask` returns the task so that the component that triggered the login can await and react after the task is complete. +* The `LoginWithExternalProviderAsync` method is implemented by the developer to log in the user with the identity provider's SDK. For more information, see your identity provider's documentation. The authenticated user (`authenticatedUser`) is a new based on a new . + +:::zone pivot="maui" + +In the `MauiProgram.CreateMauiApp` method of `MainWindow.cs`, add the authorization services and the Blazor abstraction to the service collection: + +```csharp +builder.Services.AddAuthorizationCore(); +builder.Services.TryAddScoped(); +``` + +:::zone-end + +:::zone pivot="wpf" + +In the `MainWindow`'s constructor (`MainWindow.xaml.cs`), add the authorization services and the Blazor abstraction to the service collection: + +```csharp +serviceCollection.AddAuthorizationCore(); +serviceCollection.TryAddScoped(); +``` + +:::zone-end + +:::zone pivot="winforms" + +In the `Form1`'s constructor (`Form1.cs`), add the authorization services and the Blazor abstraction to the service collection: + +```csharp +services.AddAuthorizationCore(); +services.TryAddScoped(); +``` + +:::zone-end + +The following `LoginComponent` component demonstrates how to log in a user. In a typical app, the `LoginComponent` component is only shown in a parent component if the user isn't logged into the app. + +`Shared/LoginComponent.razor`: + +```razor +@inject AuthenticationStateProvider AuthenticationStateProvider + + + +@code +{ + public async Task Login() + { + await ((ExternalAuthStateProvider)AuthenticationStateProvider) + .LoginAsync(); + } +} +``` + +The following `LogoutComponent` component demonstrates how to log out a user. In a typical app, the `LogoutComponent` component is only shown in a parent component if the user is logged into the app. + +`Shared/LogoutComponent.razor`: + +```razor +@inject AuthenticationStateProvider AuthenticationStateProvider + + + +@code +{ + public async Task Logout() + { + await ((ExternalAuthStateProvider)AuthenticationStateProvider) + .Logout(); + } +} +``` + +## Accessing other authentication information + +Blazor doesn't define an abstraction to deal with other credentials, such as access tokens to use for HTTP requests to web APIs. We recommend following the identity provider's guidance to manage the user's credentials with the primitives that the identity provider's SDK provides. + +It's common for identity provider SDKs to use a token store for user credentials stored in the device. If the SDK's token store primitive is added to the service container, consume the SDK's primitive within the app. + +The Blazor framework isn't aware of a user's authentication credentials and doesn't interact with credentials in any way, so the app's code is free to follow whatever approach you deem most convenient. However, follow the general security guidance in the next section, [Other authentication security considerations](#other-authentication-security-considerations), when implementing authentication code in an app. + +## Other authentication security considerations + +The authentication process is external to Blazor, and we recommend that developers access the identity provider's guidance for additional security guidance. + +When implementing authentication: + +* Avoid authentication in the context of the Web View. For example, avoid using a JavaScript OAuth library to perform the authentication flow. In a single-page app, authentication tokens aren't hidden in JavaScript and can be easily discovered by malicious users and used for nefarious purposes. Native apps don't suffer this risk because native apps are only able to obtain tokens outside of the browser context, which means that rogue third-party scripts can't steal the tokens and compromise the app. +* Avoid implementing the authentication workflow yourself. In most cases, platform libraries securely handle the authentication workflow, using the system's browser instead of using a custom Web View that can be hijacked. +* Avoid using the platform's Web View control to perform authentication. Instead, rely on the system's browser when possible. +* Avoid passing the tokens to the document context (JavaScript). In some situations, a JavaScript library within the document is required to perform an authorized call to an external service. Instead of making the token available to JavaScript via JS interop: + * Provide a generated temporary token to the library and within the Web View. + * Intercept the outgoing network request in code. + * Replace the temporary token with the real token and confirm that the destination of the request is valid. + +## Additional resources + +* +* + +::: moniker-end diff --git a/aspnetcore/blazor/security/server/index.md b/aspnetcore/blazor/security/server/index.md index 9d4bf9180206..82dd67cff154 100644 --- a/aspnetcore/blazor/security/server/index.md +++ b/aspnetcore/blazor/security/server/index.md @@ -12,7 +12,7 @@ uid: blazor/security/server/index This article explains how to secure Blazor Server apps as ASP.NET Core applications. -:::moniker range=">= aspnetcore-6.0" +:::moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" Blazor Server apps are configured for security in the same manner as ASP.NET Core apps. For more information, see the articles under . Topics under this overview apply specifically to Blazor Server. @@ -494,3 +494,162 @@ Using the `CustomAuthStateProvider` in the preceding example, all users are auth * Additional scenarios and use cases, including manual scheme configuration, request path changes for correct request routing, and forwarding the request scheme for Linux and non-IIS reverse proxies. :::moniker-end + +:::moniker range=">= aspnetcore-7.0" + +Blazor Server apps are configured for security in the same manner as ASP.NET Core apps. For more information, see the articles under . Topics under this overview apply specifically to Blazor Server. + +## Blazor Server project template + +The [Blazor Server project template](xref:blazor/project-structure) can be configured for authentication when the project is created. + +# [Visual Studio](#tab/visual-studio) + +Follow the Visual Studio guidance in to create a new Blazor Server project with an authentication mechanism. + +After choosing the **Blazor Server App** template in the **Create a new ASP.NET Core Web Application** dialog, select **Change** under **Authentication**. + +A dialog opens to offer the same set of authentication mechanisms available for other ASP.NET Core projects: + +* **No Authentication** +* **Individual User Accounts**: User accounts can be stored: + * Within the app using ASP.NET Core's [Identity](xref:security/authentication/identity) system. + * With [Azure AD B2C](xref:security/authentication/azure-ad-b2c). +* **Work or School Accounts** +* **Windows Authentication** + +# [Visual Studio Code](#tab/visual-studio-code) + +Follow the Visual Studio Code guidance in to create a new Blazor Server project with an authentication mechanism: + +```dotnetcli +dotnet new blazorserver -o {APP NAME} -au {AUTHENTICATION} +``` + +Permissible authentication values (`{AUTHENTICATION}`) are shown in the following table. + +| Authentication mechanism | Description | +| ------------------------ | ----------- | +| `None` (default) | No authentication | +| `Individual` | Users stored in the app with ASP.NET Core Identity | +| `IndividualB2C` | Users stored in [Azure AD B2C](xref:security/authentication/azure-ad-b2c) | +| `SingleOrg` | Organizational authentication for a single tenant | +| `MultiOrg` | Organizational authentication for multiple tenants | +| `Windows` | Windows Authentication | + +Using the `-o|--output` option, the command uses the value provided for the `{APP NAME}` placeholder to: + +* Create a folder for the project. +* Name the project. + +For more information, see the [`dotnet new`](/dotnet/core/tools/dotnet-new) command in the .NET Core Guide. + +# [Visual Studio for Mac](#tab/visual-studio-mac) + +1. Follow the Visual Studio for Mac guidance in to create a Blazor Server app. + +1. Select **Individual Authentication (in-app)** from the **Authentication** dropdown list. + +1. The app is created for individual users stored in the app with ASP.NET Core Identity. + +# [.NET Core CLI](#tab/netcore-cli/) + +Create a new Blazor Server project with an authentication mechanism using the following command in a command shell: + +```dotnetcli +dotnet new blazorserver -o {APP NAME} -au {AUTHENTICATION} +``` + +Permissible authentication values (`{AUTHENTICATION}`) are shown in the following table. + +| Authentication mechanism | Description | +| ------------------------ | ----------- | +| `None` (default) | No authentication | +| `Individual` | Users stored in the app with ASP.NET Core Identity | +| `IndividualB2C` | Users stored in [Azure AD B2C](xref:security/authentication/azure-ad-b2c) | +| `SingleOrg` | Organizational authentication for a single tenant | +| `MultiOrg` | Organizational authentication for multiple tenants | +| `Windows` | Windows Authentication | + +Using the `-o|--output` option, the command uses the value provided for the `{APP NAME}` placeholder to: + +* Create a folder for the project. +* Name the project. + +For more information: + +* See the [`dotnet new`](/dotnet/core/tools/dotnet-new) command in the .NET Core Guide. +* Execute the help command for the Blazor Server template (`blazorserver`) in a command shell: + + ```dotnetcli + dotnet new blazorserver --help + ``` + +--- + +## Scaffold Identity + +For more information on scaffolding Identity into a Blazor Server project, see . + +## Additional claims and tokens from external providers + +To store additional claims from external providers, see . + +## Azure App Service on Linux with Identity Server + +Specify the issuer explicitly when deploying to Azure App Service on Linux with Identity Server. For more information, see . + +## Notification about authentication state changes + +If the app determines that the underlying authentication state data has changed (for example, because the user signed out or another user has changed their roles), a [custom `AuthenticationStateProvider`](#implement-a-custom-authenticationstateprovider) can optionally invoke the method on the base class. This notifies consumers of the authentication state data (for example, ) to rerender using the new data. + +## Implement a custom `AuthenticationStateProvider` + +If the app requires a custom provider, implement and override `GetAuthenticationStateAsync`: + +```csharp +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components.Authorization; + +public class CustomAuthStateProvider : AuthenticationStateProvider +{ + public override Task GetAuthenticationStateAsync() + { + var identity = new ClaimsIdentity(new[] + { + new Claim(ClaimTypes.Name, "mrfibuli"), + }, "Fake authentication type"); + + var user = new ClaimsPrincipal(identity); + + return Task.FromResult(new AuthenticationState(user)); + } +} +``` + +The `CustomAuthStateProvider` service is registered in `Program.cs` ***after*** the call to : + +```csharp +using Microsoft.AspNetCore.Components.Authorization; + +... + +builder.Services.AddServerSideBlazor(); + +... + +builder.Services.TryAddScoped(); +``` + +Using the `CustomAuthStateProvider` in the preceding example, all users are authenticated with the username `mrfibuli`. + +## Additional resources + +* [Quickstart: Add sign-in with Microsoft to an ASP.NET Core web app](/azure/active-directory/develop/quickstart-v2-aspnet-core-webapp) +* [Quickstart: Protect an ASP.NET Core web API with Microsoft identity platform](/azure/active-directory/develop/quickstart-v2-aspnet-core-web-api) +* : Includes guidance on: + * Using Forwarded Headers Middleware to preserve HTTPS scheme information across proxy servers and internal networks. + * Additional scenarios and use cases, including manual scheme configuration, request path changes for correct request routing, and forwarding the request scheme for Linux and non-IIS reverse proxies. + +:::moniker-end diff --git a/aspnetcore/blazor/security/webassembly/additional-scenarios.md b/aspnetcore/blazor/security/webassembly/additional-scenarios.md index d561f95d7e1c..6d67b9eeb5db 100644 --- a/aspnetcore/blazor/security/webassembly/additional-scenarios.md +++ b/aspnetcore/blazor/security/webassembly/additional-scenarios.md @@ -1235,7 +1235,6 @@ The preceding example sets redirect URIs with regular string literals. The follo "RedirectUri": "https://localhost:5001/authentication/login-callback" } ``` - ## Additional resources @@ -4662,7 +4661,7 @@ using Microsoft.AspNetCore.Components.WebAssembly.Authentication; ... builder.Services.AddRazorPages(); -builder.Services.AddScoped(); Client.Program.ConfigureCommonServices(services); @@ -5031,7 +5030,6 @@ The preceding example sets redirect URIs with regular string literals. The follo "RedirectUri": "https://localhost:5001/authentication/login-callback" } ``` - ## Additional resources