pull/29384/head
guardrex 2023-05-31 09:12:51 -04:00
parent 51665f4600
commit 1a46d59266
5 changed files with 43 additions and 150 deletions

View File

@ -16,7 +16,10 @@ This article explains how to configure Blazor Server for additional security sce
## Pass tokens to a Blazor Server app
Tokens available outside of the Razor components in a Blazor Server app can be passed to components with the approach described in this section. The example in this section focuses on passing access and refresh tokens to the Blazor app, but the approach is valid for other HTTP context state.
Tokens available outside of the Razor components in a Blazor Server app can be passed to components with the approach described in this section. The example in this section focuses on passing access, refresh, and [anti-request forgery (XSRF) token](xref:security/anti-request-forgery) tokens to the Blazor app, but the approach is valid for other HTTP context state.
> [!NOTE]
> Passing the XSRF token to Razor components is useful in scenarios where components POST to Identity or other endpoints that require validation. If your app only requires access and refresh tokens, you can remove the XSRF token code from the following example.
Authenticate the Blazor Server app as you would with a regular Razor Pages or MVC app. Provision and save the tokens to the authentication cookie.
@ -98,15 +101,10 @@ public class TokenProvider
{
public string? AccessToken { get; set; }
public string? RefreshToken { get; set; }
public string? XsrfToken { get; set; }
}
```
If Razor components require an [anti-request forgery (XSRF) token](xref:security/anti-request-forgery) to POST to Identity or other endpoints, add a property for an XSRF token to the `TokenProvider`:
```csharp
public string? XsrfToken { get; set; }
```
:::moniker-end
:::moniker range="< aspnetcore-6.0"
@ -116,15 +114,10 @@ public class TokenProvider
{
public string AccessToken { get; set; }
public string RefreshToken { get; set; }
public string XsrfToken { get; set; }
}
```
If Razor components require an [anti-request forgery (XSRF) token](xref:security/anti-request-forgery) to POST to Identity or other endpoints, add a property for an XSRF token to the `TokenProvider`:
```csharp
public string XsrfToken { get; set; }
```
:::moniker-end
:::moniker range=">= aspnetcore-6.0"
@ -166,15 +159,10 @@ public class InitialApplicationState
{
public string? AccessToken { get; set; }
public string? RefreshToken { get; set; }
public string? XsrfToken { get; set; }
}
```
If Razor components require an [anti-request forgery (XSRF) token](xref:security/anti-request-forgery) to POST to Identity or other endpoints, add a property for an XSRF token to the `InitialApplicationState`:
```csharp
public string? XsrfToken { get; set; }
```
:::moniker-end
:::moniker range="< aspnetcore-6.0"
@ -184,15 +172,10 @@ public class InitialApplicationState
{
public string AccessToken { get; set; }
public string RefreshToken { get; set; }
public string XsrfToken { get; set; }
}
```
If Razor components require an [anti-request forgery (XSRF) token](xref:security/anti-request-forgery) to POST to Identity or other endpoints, add a property for an XSRF token to the `InitialApplicationState`:
```csharp
public string XsrfToken { get; set; }
```
:::moniker-end
:::moniker range=">= aspnetcore-7.0"
@ -215,6 +198,7 @@ In the `Pages/_Host.cshtml` file, create and instance of `InitialApplicationStat
```cshtml
@using Microsoft.AspNetCore.Authentication
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
...
@ -222,23 +206,14 @@ In the `Pages/_Host.cshtml` file, create and instance of `InitialApplicationStat
var tokens = new InitialApplicationState
{
AccessToken = await HttpContext.GetTokenAsync("access_token"),
RefreshToken = await HttpContext.GetTokenAsync("refresh_token")
RefreshToken = await HttpContext.GetTokenAsync("refresh_token"),
XsrfToken = Xsrf.GetAndStoreTokens(HttpContext).RequestToken
};
}
<component ... param-InitialState="tokens" ... />
```
If Razor components require an [anti-request forgery (XSRF) token](xref:security/anti-request-forgery) to POST to Identity or other endpoints, add the following lines to `_Host.cshtml` to establish the token:
```csharp
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
...
XsrfToken = Xsrf.GetAndStoreTokens(HttpContext).RequestToken
```
In the `App` component (`App.razor`), resolve the service and initialize it with the data from the parameter:
:::moniker range=">= aspnetcore-6.0"
@ -256,18 +231,13 @@ In the `App` component (`App.razor`), resolve the service and initialize it with
{
TokenProvider.AccessToken = InitialState?.AccessToken;
TokenProvider.RefreshToken = InitialState?.RefreshToken;
TokenProvider.XsrfToken = InitialState?.XsrfToken;
return base.OnInitializedAsync();
}
}
```
If Razor components require an [anti-request forgery (XSRF) token](xref:security/anti-request-forgery) to POST to Identity or other endpoints, add the following lines to the `App` component to to assign the `InitialState.XsrfToken`:
```csharp
TokenProvider.XsrfToken = InitialState?.XsrfToken;
```
:::moniker-end
:::moniker range="< aspnetcore-6.0"
@ -285,18 +255,13 @@ TokenProvider.XsrfToken = InitialState?.XsrfToken;
{
TokenProvider.AccessToken = InitialState.AccessToken;
TokenProvider.RefreshToken = InitialState.RefreshToken;
TokenProvider.XsrfToken = InitialState.XsrfToken;
return base.OnInitializedAsync();
}
}
```
If Razor components require an [anti-request forgery (XSRF) token](xref:security/anti-request-forgery) to POST to Identity or other endpoints, add the following lines to the `App` component to to assign the `InitialState.XsrfToken`:
```csharp
TokenProvider.XsrfToken = InitialState.XsrfToken;
```
:::moniker-end
> [!NOTE]
@ -381,7 +346,9 @@ public class WeatherForecastService
:::moniker-end
For an XSRF token passed to a component, inject the `TokenProvider` and add the XSRF token to the POST request. The following example adds the token to a logout endpoint POST. The scenario for the following example is that the logout endpoint (`Areas/Identity/Pages/Account/Logout.cshtml`) doesn't specify an <xref:Microsoft.AspNetCore.Mvc.IgnoreAntiforgeryTokenAttribute> (`@attribute [IgnoreAntiforgeryToken]`) because it performs some action in addition to a normal logout operation that must be protected. The endpoint requires a valid XSRF token to successfully process the request.
For an XSRF token passed to a component, inject the `TokenProvider` and add the XSRF token to the POST request. The following example adds the token to a logout endpoint POST. The scenario for the following example is that the logout endpoint (`Areas/Identity/Pages/Account/Logout.cshtml`, [scaffolded into the app](xref:security/authentication/scaffold-identity#scaffold-identity-into-a-blazor-server-project)) doesn't specify an <xref:Microsoft.AspNetCore.Mvc.IgnoreAntiforgeryTokenAttribute> (`@attribute [IgnoreAntiforgeryToken]`) because it performs some action in addition to a normal logout operation that must be protected. The endpoint requires a valid XSRF token to successfully process the request.
In a component that presents a **Logout** button to authorized users:
```razor
@inject TokenProvider TokenProvider
@ -390,9 +357,6 @@ For an XSRF token passed to a component, inject the `TokenProvider` and add the
<AuthorizeView>
<Authorized>
<a href="Identity/Account/Manage/Index">
Hello, @context.User.Identity.Name!
</a>
<form action="/Identity/Account/Logout?returnUrl=%2F" method="post">
<button class="nav-link btn btn-link" type="submit">Logout</button>
<input name="__RequestVerificationToken" type="hidden"
@ -403,7 +367,6 @@ For an XSRF token passed to a component, inject the `TokenProvider` and add the
...
</NotAuthorized>
</AuthorizeView>
```
## Set the authentication scheme

View File

@ -1,5 +1,3 @@
:::moniker range=">= aspnetcore-6.0"
Run the Identity scaffolder:
# [Visual Studio](#tab/visual-studio)
@ -7,13 +5,13 @@ Run the Identity scaffolder:
* From **Solution Explorer**, right-click on the project > **Add** > **New Scaffolded Item**.
* From the left pane of the **Add New Scaffolded Item** dialog, select **Identity**. Select **Identity** in the center pane. Select the **Add** button.
* In the **Add Identity** dialog, select the options you want.
* If you have an existing, customized layout page for Identity, select your existing layout page to avoid overwriting your layout with incorrect markup by the scaffolder. When an existing `_Layout.cshtml` file is selected, it is **not** overwritten. For example:
* `~/Pages/Shared/_Layout.cshtml` for Razor Pages or Blazor Server projects with existing Razor Pages infrastructure
* `~/Views/Shared/_Layout.cshtml` for MVC projects or Blazor Server projects with existing MVC infrastructure
* Data context:
* If you have an existing, customized layout page for Identity (`_Layout.cshtml`), select your existing layout page to avoid overwriting your layout with incorrect markup by the scaffolder. For example, select either:
* `Pages/Shared/_Layout.cshtml` for Razor Pages or Blazor Server projects with existing Razor Pages infrastructure.
* `Views/Shared/_Layout.cshtml` for MVC projects or Blazor Server projects with existing MVC infrastructure.
* For the data context (**DbContext class**):
* Select your data context class. You must select at least one file to add your data context.
* To create a new user context and possibly create a custom user class for Identity, select the **+** button to create a new **Data context class**. Accept the default value or specify a class (for example, `MyApplication.Data.ApplicationDbContext`). If you're creating a new user context, you aren't required to select a file to override.
* Select the **Add** button.
* To create a data context and possibly create a new user class for Identity, select the **+** button. Accept the default value or specify a class (for example, `Contoso.Data.ApplicationDbContext` for a company named "Contoso"). To create a new user class, select the **+** button for **User class** and specify the class (for example, `ContosoUser` for a company named "Contoso").
* Select the **Add** button to run the scaffolder.
# [.NET Core CLI](#tab/netcore-cli)
@ -48,76 +46,13 @@ In the project folder, run the Identity scaffolder with the options you want. Fo
dotnet aspnet-codegenerator identity -dc MyApplication.Data.ApplicationDbContext --files "Account.Register;Account.Login"
```
PowerShell uses semicolon as a command separator. When using PowerShell, escape the semi-colons in the file list or put the file list in double quotes. For example:
> [!NOTE]
> PowerShell uses semicolon as a command separator. When using PowerShell, escape the semicolons in the file list or put the file list in double quotes. For example:
```dotnetcli
dotnet aspnet-codegenerator identity -dc MyApplication.Data.ApplicationDbContext --files "Account.Register;Account.Login;Account.Logout"
```
If you run the Identity scaffolder without specifying the `--files` flag or the `--useDefaultUI` flag, all the available Identity UI pages will be created in your project.
If you run the Identity scaffolder without specifying the `--files` flag or the `--useDefaultUI` flag, all the available Identity UI pages are created in the project.
---
:::moniker-end
:::moniker range="< aspnetcore-6.0"
Run the Identity scaffolder:
# [Visual Studio](#tab/visual-studio)
* From **Solution Explorer**, right-click on the project > **Add** > **New Scaffolded Item**.
* From the left pane of the **Add Scaffold** dialog, select **Identity** > **Add**.
* In the **Add Identity** dialog, select the options you want:
* If you have an existing, customized layout page for Identity, select your existing layout page to avoid overwriting your layout with incorrect markup by the scaffolder. When an existing `_Layout.cshtml` file is selected, it is **not** overwritten. For example:
* `~/Pages/Shared/_Layout.cshtml` for Razor Pages or Blazor Server projects with existing Razor Pages infrastructure
* `~/Views/Shared/_Layout.cshtml` for MVC projects or Blazor Server projects with existing MVC infrastructure
* Data context:
* Select your data context class. You must select at least one file to add your data context.
* To create a new user context and possibly create a custom user class for Identity, select the **+** button to create a new **Data context class**. Accept the default value or specify a class (for example, `MyApplication.Data.ApplicationDbContext`). If you're creating a new user context, you aren't required to select a file to override.
* Select the **Add** button.
# [.NET Core CLI](#tab/netcore-cli)
If you have not previously installed the ASP.NET Core scaffolder, install it now:
```dotnetcli
dotnet tool install -g dotnet-aspnet-codegenerator
```
Add required NuGet package references to the project file (`.csproj`). Run the following commands in the project directory:
```dotnetcli
dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
dotnet add package Microsoft.AspNetCore.Identity.UI
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Tools
```
Run the following command to list the Identity scaffolder options:
```dotnetcli
dotnet aspnet-codegenerator identity -h
```
[!INCLUDE[](~/includes/scaffoldTFM.md)]
In the project folder, run the Identity scaffolder with the options you want. For example, to setup identity with the default UI and the minimum number of files, run the following command. Use the correct fully qualified name for your DB context:
```dotnetcli
dotnet aspnet-codegenerator identity -dc MyApplication.Data.ApplicationDbContext --files "Account.Register;Account.Login"
```
PowerShell uses semicolon as a command separator. When using PowerShell, escape the semi-colons in the file list or put the file list in double quotes. For example:
```dotnetcli
dotnet aspnet-codegenerator identity -dc MyApplication.Data.ApplicationDbContext --files "Account.Register;Account.Login;Account.Logout"
```
If you run the Identity scaffolder without specifying the `--files` flag or the `--useDefaultUI` flag, all the available Identity UI pages will be created in your project.
---
:::moniker-end

View File

@ -3,14 +3,15 @@ Run the Identity scaffolder:
# [Visual Studio](#tab/visual-studio)
* From **Solution Explorer**, right-click on the project > **Add** > **New Scaffolded Item**.
* From the left pane of the **Add New Scaffolded Item** dialog, select **Identity** > **Add**.
* From the left pane of the **Add New Scaffolded Item** dialog, select **Identity**. Select **Identity** in the center pane. Select the **Add** button.
* In the **Add Identity** dialog, select the options you want.
* Select your existing layout page, or your layout file will be overwritten with incorrect markup:
* `~/Pages/Shared/_Layout.cshtml` for Razor Pages
* `~/Views/Shared/_Layout.cshtml` for MVC projects
* Blazor Server apps created from the Blazor Server template (`blazorserver`) aren't configured for Razor Pages or MVC by default. Leave the layout page entry blank.
* Select the **+** button to create a new **Data context class**. Accept the default value or specify a class (for example, `MyApplication.Data.ApplicationDbContext`).
* Select **Add**.
* If you have an existing, customized layout page for Identity (`_Layout.cshtml`), select your existing layout page to avoid overwriting your layout with incorrect markup by the scaffolder. For example, select either:
* `Pages/Shared/_Layout.cshtml` for Razor Pages or Blazor Server projects with existing Razor Pages infrastructure.
* `Views/Shared/_Layout.cshtml` for MVC projects or Blazor Server projects with existing MVC infrastructure.
* For the data context (**DbContext class**):
* Select your data context class. You must select at least one file to add your data context.
* To create a data context and possibly create a new user class for Identity, select the **+** button. Accept the default value or specify a class (for example, `Contoso.Data.ApplicationDbContext` for a company named "Contoso"). To create a new user class, select the **+** button for **User class** and specify the class (for example, `ContosoUser` for a company named "Contoso").
* Select the **Add** button to run the scaffolder.
# [.NET Core CLI](#tab/netcore-cli)

View File

@ -1,17 +1,5 @@
Install the [Microsoft.VisualStudio.Web.CodeGeneration.Design](https://www.nuget.org/packages/Microsoft.VisualStudio.Web.CodeGeneration.Design/) NuGet package:
Install the [Microsoft.VisualStudio.Web.CodeGeneration.Design](https://www.nuget.org/packages/Microsoft.VisualStudio.Web.CodeGeneration.Design/) NuGet package.
# [Visual Studio](#tab/visual-studio)
In the Visual Studio **Package Manager Console**:
```powershell
Install-Package Microsoft.VisualStudio.Web.CodeGeneration.Design
```
# [.NET Core CLI](#tab/netcore-cli)
```dotnetcli
dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
```
[!INCLUDE[](~/includes/package-reference.md)]
---

View File

@ -145,7 +145,7 @@ dotnet aspnet-codegenerator identity -dc MvcAuth.Data.ApplicationDbContext --fi
[!INCLUDE[](~/includes/scaffold-identity/id-scaffold-dlg-auth.md)]
## Scaffold Identity into a Blazor Server project
## Scaffold Identity into a Blazor Server project with authorization
[!INCLUDE[](~/includes/scaffold-identity/install-pkg.md)]
@ -159,6 +159,9 @@ dotnet aspnet-codegenerator identity -dc MvcAuth.Data.ApplicationDbContext --fi
Because Blazor Server uses Razor Pages Identity pages, the styling of the UI changes when a visitor navigates between Identity pages and components. You have two options to address the incongruous styles:
* [Custom Identity components](#custom-identity-components)
* [Use a custom layout with Blazor app styles](#use-a-custom-layout-with-blazor-app-styles)
#### Custom Identity components
ASP.NET Core Identity is designed to work in the context of HTTP request and response communication, which isn't the primary client-server communication model in Blazor apps. ASP.NET Core apps that use ASP.NET Core Identity for user management should use Razor Pages instead of Razor components for Identity-related UI, such as user registration, login, logout, and other user management tasks.
@ -454,9 +457,12 @@ Identity is configured in `Areas/Identity/IdentityHostingStartup.cs`. For more i
Because Blazor Server uses Razor Pages Identity pages, the styling of the UI changes when a visitor navigates between Identity pages and components. You have two options to address the incongruous styles:
* [Custom Identity components](#custom-identity-components)
* [Use a custom layout with Blazor app styles](#use-a-custom-layout-with-blazor-app-styles)
#### Custom Identity components
An approach to using components for Identity instead of pages is to build Identity components. Because `SignInManager` and `UserManager` aren't supported in Razor components, use API endpoints in the Blazor Server app to process user account actions.
An approach to using components for Identity instead of pages is to build Identity components. Because `SignInManager` and `UserManager` aren't supported in Razor components, use web API endpoints in the Blazor Server app to process user account actions.
#### Use a custom layout with Blazor app styles