ASP.NET Core 專案中的 Scaffold Identity

作者:Rick Anderson

ASP.NET Core 提供ASP.NET Core Identity作為Razor 類別庫。 包含 Identity 的應用程式可以套用 scaffolder,選擇性地新增類別庫中所含 IdentityRazor 的原始程式碼, (RCL) 。 建議您產生原始程式碼,以便能夠修改程式碼並變更行為。 例如,您可以指示 Scaffolder 產生註冊使用的程式碼。 產生的程式碼優先于 RCL 中的 Identity 相同程式碼。 若要完全控制 UI,而不使用預設 RCL,請參閱 建立完整 Identity UI 來源一節。

不包含驗證的應用程式可以套用 Scaffolder 以新增 RCL Identity 套件。 您可以選擇選取 Identity 要產生的程式碼。

雖然 Scaffolder 會產生大部分的必要程式碼,但您需要更新專案以完成程式。 本檔說明完成 Identity Scaffolding 更新所需的步驟。

建議您使用原始檔控制系統來顯示檔案差異,並可讓您回復變更。 在執行 Scaffolder 之後檢查 Identity 變更。

使用 Two Factor Authentication帳戶確認和密碼復原,以及搭配 Identity 的其他安全性功能時,需要服務。 當 Scaffolding Identity 時,不會產生服務或服務存根。 必須手動新增啟用這些功能的服務。 例如,請參閱 需要電子郵件確認

一般而言,使用個別帳戶建立的應用程式 不應該 建立新的資料內容。

在沒有現有授權的情況下,將 Scaffold Identity 建置成 Razor 專案

安裝 Microsoft.VisualStudio.Web.CodeGeneration.Design NuGet 套件:

在 Visual Studio 套件管理員主控台中

Install-Package Microsoft.VisualStudio.Web.CodeGeneration.Design

Identity執行 scaffolder:

  • [方案總管] 中,以滑鼠右鍵按一下專案 >[新增>Scaffolded 專案]。
  • 從 [新增 Scaffolded 專案] 對話方塊的左窗格中,選取 [ Identity>新增]。
  • 在 [新增 Identity] 對話方塊中,選取您想要的選項。
    • 選取現有的版面配置頁面,或您的版面配置檔案將會以不正確的標記覆寫:
      • ~/Pages/Shared/_Layout.cshtml 針對 Razor 頁面
      • ~/Views/Shared/_Layout.cshtml MVC 專案的
      • Blazor Server根據預設,不會針對 Razor Pages 或 MVC 設定從 Blazor Server 範本建立 (blazorserver) 的應用程式。 將版面配置頁面專案保留空白。
    • +選取按鈕以建立新的[資料] 內容類別別。 接受預設值或指定類別 (例如, MyApplication.Data.ApplicationDbContext) 。
  • 選取 [新增]。

移轉、UseAuthentication 和版面配置

產生的 Identity 資料庫程式碼需要 Entity Framework Core 移轉。 建立移轉並更新資料庫。 例如,執行下列命令:

在 Visual Studio 套件管理員主控台中

Install-Package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
Add-Migration CreateIdentitySchema
Update-Database

命令的 Add-Migration 「建立 Identity 架構」名稱參數是任意的。 "CreateIdentitySchema" 描述移轉。

版面配置變更

選擇性:將登入部分 (_LoginPartial) 新增至版面配置檔案:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - WebRPnoAuth2Auth</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
    <link rel="stylesheet" href="~/WebRPnoAuth2Auth.styles.css" asp-append-version="true" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-area="" asp-page="/Index">WebRPnoAuth2Auth</a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a>
                        </li>
                    </ul>
                    <partial name="_LoginPartial" />
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2021 - WebRPnoAuth2Auth - <a asp-area="" asp-page="/Privacy">Privacy</a>
        </div>
    </footer>

    <script src="~/lib/jquery/dist/jquery.min.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>

    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

使用授權將 Scaffold Identity 建置成 Razor 專案

安裝 Microsoft.VisualStudio.Web.CodeGeneration.Design NuGet 套件:

在 Visual Studio 套件管理員主控台中

Install-Package Microsoft.VisualStudio.Web.CodeGeneration.Design

Identity執行 scaffolder:

  • [方案總管] 中,以滑鼠右鍵按一下專案 >[新增>Scaffolded 專案]。
  • 從 [ 新增 Scaffolded 專案 ] 對話方塊的左窗格中,選取 Identity 。 在中央窗格中選取 Identity 。 選取 [新增] 按鈕。
  • 在 [新增 Identity] 對話方塊中,選取您想要的選項。
    • 選取現有的版面配置頁面,讓版面配置檔案不會以不正確的標記覆寫。 選取現有的 _Layout.cshtml 檔案時, 不會 覆寫它。 例如:
      • ~/Pages/Shared/_Layout.cshtml適用于 Razor 具有現有 Razor Pages 基礎結構的頁面或 Blazor Server 專案。
      • ~/Views/Shared/_Layout.cshtml 適用于具有現有 MVC 基礎結構的 MVC 專案或 Blazor Server 專案。
  • 若要使用現有的資料內容,請選取至少一個要覆寫的檔案。 您必須選取至少一個檔案以新增資料內容。
    • 選取您的資料內容類別別。
    • 選取 [新增]。
  • 若要建立新的使用者內容,並可能為 Identity 建立自訂使用者類別:
    • +選取按鈕以建立新的[資料] 內容類別別。 接受預設值或指定類別 (例如, MyApplication.Data.ApplicationDbContext) 。
    • 選取 [新增]。

注意:如果您要建立新的使用者內容,則不需要選取要覆寫的檔案。

Identity執行 scaffolder:

  • [方案總管] 中,以滑鼠右鍵按一下專案 >[新增>Scaffolded 專案]。
  • 從 [新增 Scaffold]對話方塊的左窗格中,選取 [ Identity>新增]。
  • 在 [新增 Identity] 對話方塊中,選取您想要的選項。
    • 選取現有的版面配置頁面,讓版面配置檔案不會以不正確的標記覆寫。 選取現有的 _Layout.cshtml 檔案時, 不會 覆寫它。 例如:
      • ~/Pages/Shared/_Layout.cshtml適用于 Razor 具有現有 Razor Pages 基礎結構的頁面或 Blazor Server 專案
      • ~/Views/Shared/_Layout.cshtml 適用于具有現有 MVC 基礎結構的 MVC 專案或 Blazor Server 專案
  • 若要使用現有的資料內容,請選取至少一個要覆寫的檔案。 您必須選取至少一個檔案以新增資料內容。
    • 選取您的資料內容類別別。
    • 選取 [新增]。
  • 若要建立新的使用者內容,並可能為 Identity 建立自訂使用者類別:
    • +選取按鈕以建立新的[資料] 內容類別別。 接受預設值或指定類別 (例如, MyApplication.Data.ApplicationDbContext) 。
    • 選取 [新增]。

注意:如果您要建立新的使用者內容,則不需要選取要覆寫的檔案。

在沒有現有授權的情況下,將 Scaffold Identity 建置成 MVC 專案

安裝 Microsoft.VisualStudio.Web.CodeGeneration.Design NuGet 套件:

在 Visual Studio 套件管理員主控台中

Install-Package Microsoft.VisualStudio.Web.CodeGeneration.Design

Identity執行 scaffolder:

  • [方案總管] 中,以滑鼠右鍵按一下專案 >[新增>Scaffolded 專案]。
  • 從 [新增 Scaffolded 專案] 對話方塊的左窗格中,選取 [ Identity>新增]。
  • 在 [新增 Identity] 對話方塊中,選取您想要的選項。
    • 選取現有的版面配置頁面,或您的版面配置檔案將會以不正確的標記覆寫:
      • ~/Pages/Shared/_Layout.cshtml 針對 Razor 頁面
      • ~/Views/Shared/_Layout.cshtml MVC 專案的
      • Blazor Server根據預設,不會針對 Razor Pages 或 MVC 設定從 Blazor Server 範本建立 (blazorserver) 的應用程式。 將版面配置頁面專案保留空白。
    • +選取按鈕以建立新的[資料] 內容類別別。 接受預設值或指定類別 (例如, MyApplication.Data.ApplicationDbContext) 。
  • 選取 [新增]。

選擇性:將登入部分 (_LoginPartial) 新增至 Views/Shared/_Layout.cshtml 檔案:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - WebRPnoAuth2Auth</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
    <link rel="stylesheet" href="~/WebRPnoAuth2Auth.styles.css" asp-append-version="true" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-area="" asp-page="/Index">WebRPnoAuth2Auth</a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a>
                        </li>
                    </ul>
                    <partial name="_LoginPartial" />
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2021 - WebRPnoAuth2Auth - <a asp-area="" asp-page="/Privacy">Privacy</a>
        </div>
    </footer>

    <script src="~/lib/jquery/dist/jquery.min.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>

    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

產生的 Identity 資料庫程式碼需要 Entity Framework Core 移轉。 建立移轉並更新資料庫。 例如,執行下列命令:

在 Visual Studio 套件管理員主控台中

Install-Package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
Add-Migration CreateIdentitySchema
Update-Database

命令的 Add-Migration 「建立 Identity 架構」名稱參數是任意的。 "CreateIdentitySchema" 描述移轉。

將 新增 MapRazorPagesProgram.cs ,如下列醒目提示的程式碼所示:

using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using WebMVCauth.Data;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");
app.MapRazorPages();

app.Run();

使用授權將 Scaffold Identity 建置成 MVC 專案

安裝 Microsoft.VisualStudio.Web.CodeGeneration.Design NuGet 套件:

在 Visual Studio 套件管理員主控台中

Install-Package Microsoft.VisualStudio.Web.CodeGeneration.Design

Identity執行 scaffolder:

  • [方案總管] 中,以滑鼠右鍵按一下專案 >[新增>Scaffolded 專案]。
  • 從 [ 新增 Scaffolded 專案 ] 對話方塊的左窗格中,選取 Identity 。 在中央窗格中選取 Identity 。 選取 [新增] 按鈕。
  • 在 [新增 Identity] 對話方塊中,選取您想要的選項。
    • 選取現有的版面配置頁面,讓版面配置檔案不會以不正確的標記覆寫。 選取現有的 _Layout.cshtml 檔案時, 不會 覆寫它。 例如:
      • ~/Pages/Shared/_Layout.cshtml適用于 Razor 具有現有 Razor Pages 基礎結構的頁面或 Blazor Server 專案。
      • ~/Views/Shared/_Layout.cshtml 適用于具有現有 MVC 基礎結構的 MVC 專案或 Blazor Server 專案。
  • 若要使用現有的資料內容,請選取至少一個要覆寫的檔案。 您必須選取至少一個檔案以新增資料內容。
    • 選取您的資料內容類別別。
    • 選取 [新增]。
  • 若要建立新的使用者內容,並可能為 Identity 建立自訂使用者類別:
    • +選取按鈕以建立新的[資料] 內容類別別。 接受預設值或指定類別 (例如, MyApplication.Data.ApplicationDbContext) 。
    • 選取 [新增]。

注意:如果您要建立新的使用者內容,則不需要選取要覆寫的檔案。

Identity執行 Scaffolder:

  • [方案總管]中,以滑鼠右鍵按一下專案 >[新增>Scaffolded 專案]。
  • 從 [新增 Scaffold] 對話方塊的左窗格中,選取 [ Identity>新增]。
  • 在 [新增 Identity] 對話方塊中,選取您想要的選項。
    • 選取現有的版面配置頁面,讓您的版面配置檔案不會以不正確的標記覆寫。 選取現有的 _Layout.cshtml 檔案時, 不會 覆寫它。 例如:
      • ~/Pages/Shared/_Layout.cshtml適用于 Razor 具有現有 Razor Pages 基礎結構的頁面或 Blazor Server 專案
      • ~/Views/Shared/_Layout.cshtml 適用于具有現有 MVC 基礎結構的 MVC 專案或 Blazor Server 專案
  • 若要使用現有的資料內容,請選取至少一個要覆寫的檔案。 您必須選取至少一個檔案,才能新增資料內容。
    • 選取您的資料內容類別別。
    • 選取 [新增]。
  • 若要建立新的使用者內容,並可能建立 的 Identity 自訂使用者類別:
    • +選取按鈕以建立新的資料內容類別別。 接受預設值,或指定類別 (例如, MyApplication.Data.ApplicationDbContext) 。
    • 選取 [新增]。

注意:如果您要建立新的使用者內容,就不需要選取要覆寫的檔案。

將 Scaffold Identity 建置成 Blazor Server 專案

安裝 Microsoft.VisualStudio.Web.CodeGeneration.Design NuGet 套件:

在 Visual Studio 套件管理員主控台中:

Install-Package Microsoft.VisualStudio.Web.CodeGeneration.Design

Identity執行 Scaffolder:

  • [方案總管]中,以滑鼠右鍵按一下專案 >[新增>Scaffolded 專案]。
  • 從 [ 新增 Scaffolded 專案 ] 對話方塊的左窗格中,選取 Identity 。 在中央窗格中選取 Identity 。 選取 [新增] 按鈕。
  • 在 [新增 Identity] 對話方塊中,選取您想要的選項。
    • 選取現有的版面配置頁面,讓您的版面配置檔案不會以不正確的標記覆寫。 選取現有的 _Layout.cshtml 檔案時, 不會 覆寫它。 例如:
      • ~/Pages/Shared/_Layout.cshtml適用于 Razor 具有現有 Razor Pages 基礎結構的頁面或 Blazor Server 專案。
      • ~/Views/Shared/_Layout.cshtml 適用于具有現有 MVC 基礎結構的 MVC 專案或 Blazor Server 專案。
  • 若要使用現有的資料內容,請選取至少一個要覆寫的檔案。 您必須選取至少一個檔案,才能新增資料內容。
    • 選取您的資料內容類別別。
    • 選取 [新增]。
  • 若要建立新的使用者內容,並可能建立 的 Identity 自訂使用者類別:
    • +選取按鈕以建立新的資料內容類別別。 接受預設值,或指定類別 (例如, MyApplication.Data.ApplicationDbContext) 。
    • 選取 [新增]。

注意:如果您要建立新的使用者內容,就不需要選取要覆寫的檔案。

Identity執行 Scaffolder:

  • [方案總管]中,以滑鼠右鍵按一下專案 >[新增>Scaffolded 專案]。
  • 從 [新增 Scaffold] 對話方塊的左窗格中,選取 [ Identity>新增]。
  • 在 [新增 Identity] 對話方塊中,選取您想要的選項。
    • 選取現有的版面配置頁面,讓您的版面配置檔案不會以不正確的標記覆寫。 選取現有的 _Layout.cshtml 檔案時, 不會 覆寫它。 例如:
      • ~/Pages/Shared/_Layout.cshtml適用于 Razor 具有現有 Razor Pages 基礎結構的頁面或 Blazor Server 專案
      • ~/Views/Shared/_Layout.cshtml 適用于具有現有 MVC 基礎結構的 MVC 專案或 Blazor Server 專案
  • 若要使用現有的資料內容,請選取至少一個要覆寫的檔案。 您必須選取至少一個檔案,才能新增資料內容。
    • 選取您的資料內容類別別。
    • 選取 [新增]。
  • 若要建立新的使用者內容,並可能建立 的 Identity 自訂使用者類別:
    • +選取按鈕以建立新的資料內容類別別。 接受預設值,或指定類別 (例如, MyApplication.Data.ApplicationDbContext) 。
    • 選取 [新增]。

注意:如果您要建立新的使用者內容,就不需要選取要覆寫的檔案。

移轉

產生的 Identity 資料庫程式碼需要 Entity Framework Core 移轉。 建立移轉並更新資料庫。 例如,執行下列命令:

在 Visual Studio 套件管理員主控台中:

Install-Package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
Add-Migration CreateIdentitySchema
Update-Database

命令的 Add-Migration 「建立 Identity 架構」名稱參數是任意的。 "CreateIdentitySchema" 描述移轉。

將 XSRF 權杖傳遞至應用程式

權杖可以傳遞至元件:

  • 將驗證權杖布建並儲存至驗證 cookie 時,可以傳遞至元件。
  • Razor 元件無法直接使用 HttpContext ,因此無法取得 反要求偽造 (XSRF) 權杖 至 POST 的 Identity 登出端點 /Identity/Account/Logout 。 XSRF 權杖可以傳遞至元件。

如需詳細資訊,請參閱 ASP.NET 核心 Blazor Server 其他安全性案例

在 檔案中 Pages/_Host.cshtml ,在將權杖新增至 InitialApplicationStateTokenProvider 類別之後建立權杖:

@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf

...

var tokens = new InitialApplicationState
{
    ...

    XsrfToken = Xsrf.GetAndStoreTokens(HttpContext).RequestToken
};

更新元件 App (App.razor) 以指派 InitialState.XsrfToken

@inject TokenProvider TokenProvider

...

TokenProvider.XsrfToken = InitialState.XsrfToken;

TokenProvider本主題中示範的服務會用於 LoginDisplay 下列版面配置和驗證流程變更一節中的元件。

註冊權杖提供者服務

如果使用 權杖提供者服務,請在 中 Program.cs 註冊服務:

builder.Services.AddScoped<TokenProvider>();

版面配置和驗證流程變更

RedirectToLogin將元件 (RedirectToLogin.razor) 新增至專案根目錄中的應用程式 Shared 資料夾:

@inject NavigationManager Navigation
@code {
    protected override void OnInitialized()
    {
        Navigation.NavigateTo("Identity/Account/Login?returnUrl=" +
            Uri.EscapeDataString(Navigation.Uri), true);
    }
}

LoginDisplay將元件 (LoginDisplay.razor) 新增至應用程式 Shared 的資料夾。 在下列範例中, 權杖提供者服務TokenProvider 會提供 POST 登出 Identity 端點之 HTML 表單的 XSRF 權杖:

@using Microsoft.AspNetCore.Components.Authorization
@inject NavigationManager Navigation
@inject TokenProvider TokenProvider

<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" 
                value="@TokenProvider.XsrfToken">
        </form>
    </Authorized>
    <NotAuthorized>
        <a href="Identity/Account/Register">Register</a>
        <a href="Identity/Account/Login">Login</a>
    </NotAuthorized>
</AuthorizeView>

MainLayout 元件 (Shared/MainLayout.razor) 中,將 LoginDisplay 元件新增至頂端資料列 <div> 元素的內容:

<div class="top-row px-4 auth">
    <LoginDisplay />
    <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
</div>

樣式驗證端點

由於 Blazor Server 使用 Razor Pages Identity 頁面,因此當訪客在頁面和元件之間 Identity 巡覽時,UI 的樣式會變更。 您有兩個選項可解決不一致樣式:

建置 Identity 元件

使用 元件而非 Identity 頁面的方法,就是建置 Identity 元件。 由於 SignInManager 元件不支援 Razor 和 UserManager ,因此請在應用程式中使用 API 端點 Blazor Server 來處理使用者帳戶動作。

搭配 Blazor 應用程式樣式使用自訂版面配置

Identity您可以修改頁面版面配置和樣式,以產生使用預設 Blazor 主題的頁面。

注意

本節中的範例只是自訂的起點。 可能需要額外的工作,才能獲得最佳使用者體驗。

建立新的 NavMenu_IdentityLayout 元件 (Shared/NavMenu_IdentityLayout.razor) 。 針對元件的標記和程式碼,請使用應用程式 NavMenu 元件 Shared/NavMenu.razor () 相同的內容。 移除任何 NavLink 無法匿名連線的元件,因為元件中的 RedirectToLogin 自動重新導向失敗,因為需要驗證或授權的元件。

在 檔案中 Pages/Shared/Layout.cshtml ,進行下列變更:

  • 將指示詞新增 Razor 至檔案頂端,以在 資料夾中使用標籤協助程式和應用程式的元件 Shared

    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    @using {APPLICATION ASSEMBLY}.Shared
    

    將 取代 {APPLICATION ASSEMBLY} 為應用程式的元件名稱。

  • <base>將標籤和 Blazor 樣式表單 <link> 新增至 <head> 內容:

    <base href="~/" />
    <link rel="stylesheet" href="~/css/site.css" />
    
  • 將標籤的內容 <body> 變更為下列內容:

    <div class="sidebar" style="float:left">
        <component type="typeof(NavMenu_IdentityLayout)" 
            render-mode="ServerPrerendered" />
    </div>
    
    <div class="main" style="padding-left:250px">
        <div class="top-row px-4">
            @{
                var result = Engine.FindView(ViewContext, "_LoginPartial", 
                    isMainPage: false);
            }
            @if (result.Success)
            {
                await Html.RenderPartialAsync("_LoginPartial");
            }
            else
            {
                throw new InvalidOperationException("The default Identity UI " +
                    "layout requires a partial view '_LoginPartial'.");
            }
            <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
        </div>
    
        <div class="content px-4">
            @RenderBody()
        </div>
    </div>
    
    <script src="~/Identity/lib/jquery/dist/jquery.min.js"></script>
    <script src="~/Identity/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
    <script src="~/Identity/js/site.js" asp-append-version="true"></script>
    @RenderSection("Scripts", required: false)
    <script src="_framework/blazor.server.js"></script>
    

獨立或託管 Blazor WebAssembly 的應用程式

Blazor WebAssembly用戶端應用程式會使用自己的 Identity UI 方法,而且無法使用 ASP.NET Core Identity Scaffolding。 裝載解決方案的 Blazor 伺服器端 ASP.NET 核心應用程式可以遵循 Razor 本文中的 Pages/MVC 指引,而且設定方式就像支援 Identity 的任何其他 ASP.NET Core 應用程式一樣。

架構 Blazor 不包含 Razor UI 頁面的 Identity 元件版本。 Identity UI Razor 元件可以自訂建置或從不支援的協力廠商來源取得。

如需詳細資訊,請參閱Blazor 安全性和 Identity 文章

建立完整的 Identity UI 來源

若要維持 UI 的完整控制權 Identity ,請執行 Identity Scaffolder 並選取 [覆寫所有檔案]。

密碼組態

如果在 PasswordOptionsStartup.ConfigureServices 設定 ,[StringLength]則 Scaffold 頁面中的屬性可能需要 Password 屬性組 Identity 態。 InputModelPassword 屬性可在下列檔案中找到:

  • Areas/Identity/Pages/Account/Register.cshtml.cs
  • Areas/Identity/Pages/Account/ResetPassword.cshtml.cs

停用頁面

本節說明如何停用註冊頁面,但方法可用來停用任何頁面。

若要停用使用者註冊:

  • Scaffold Identity 。 包含 Account.Register、Account.Login 和 Account.RegisterConfirmation。 例如:

    dotnet aspnet-codegenerator identity -dc RPauth.Data.ApplicationDbContext --files "Account.Register;Account.Login;Account.RegisterConfirmation"
    
  • 更新 Areas/Identity/Pages/Account/Register.cshtml.cs ,讓使用者無法從此端點註冊:

    public class RegisterModel : PageModel
    {
        public IActionResult OnGet()
        {
            return RedirectToPage("Login");
        }
    
        public IActionResult OnPost()
        {
            return RedirectToPage("Login");
        }
    }
    
  • 更新 Areas/Identity/Pages/Account/Register.cshtml 以與上述變更一致:

    @page
    @model RegisterModel
    @{
        ViewData["Title"] = "Go to Login";
    }
    
    <h1>@ViewData["Title"]</h1>
    
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Login">Login</a>
    </li>
    
  • 將註冊連結批註化或從中移除 Areas/Identity/Pages/Account/Login.cshtml

    @*
    <p>
        <a asp-page="./Register" asp-route-returnUrl="@Model.ReturnUrl">Register as a new user</a>
    </p>
    *@
    
  • 更新 [區域/ Identity /頁面/帳戶/RegisterConfirmation] 頁面。

    • 從 cshtml 檔案中移除程式碼和連結。
    • PageModel 移除確認碼:
    [AllowAnonymous]
      public class RegisterConfirmationModel : PageModel
      {
          public IActionResult OnGet()
          {  
              return Page();
          }
      }
    

使用另一個應用程式新增使用者

提供在 Web 應用程式外部新增使用者的機制。 新增使用者的選項包括:

  • 專用的系統管理員 Web 應用程式。
  • 主控台應用程式。

下列程式碼概述新增使用者的一種方法:

  • 使用者清單會讀入記憶體中。
  • 每個使用者都會產生強式唯一密碼。
  • 使用者會新增至 Identity 資料庫。
  • 系統會通知使用者,並告知使用者變更密碼。
public class Program
{
    public static void Main(string[] args)
    {
        var host = CreateHostBuilder(args).Build();

        using (var scope = host.Services.CreateScope())
        {
            var services = scope.ServiceProvider;

            try
            {
                var context = services.GetRequiredService<AppDbCntx>();
                context.Database.Migrate();

                var config = host.Services.GetRequiredService<IConfiguration>();
                var userList = config.GetSection("userList").Get<List<string>>();

                SeedData.Initialize(services, userList).Wait();
            }
            catch (Exception ex)
            {
                var logger = services.GetRequiredService<ILogger<Program>>();
                logger.LogError(ex, "An error occurred adding users.");
            }
        }

        host.Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

下列程式碼概述新增使用者:


public static async Task Initialize(IServiceProvider serviceProvider,
                                    List<string> userList)
{
    var userManager = serviceProvider.GetService<UserManager<IdentityUser>>();

    foreach (var userName in userList)
    {
        var userPassword = GenerateSecurePassword();
        var userId = await EnsureUser(userManager, userName, userPassword);

        NotifyUser(userName, userPassword);
    }
}

private static async Task<string> EnsureUser(UserManager<IdentityUser> userManager,
                                             string userName, string userPassword)
{
    var user = await userManager.FindByNameAsync(userName);

    if (user == null)
    {
        user = new IdentityUser(userName)
        {
            EmailConfirmed = true
        };
        await userManager.CreateAsync(user, userPassword);
    }

    return user.Id;
}

針對生產案例,可以遵循類似的方法。

防止發佈靜態 Identity 資產

若要防止將靜態 Identity 資產發佈至 Web 根目錄,請參閱 Identity ASP.NET Core 簡介

ASP.NET Core 提供ASP.NET Core Identity作為Razor 類別庫。 包含 Identity 的應用程式可以套用 scaffolder,以選擇性地新增類別庫 (RCL) 中包含的 IdentityRazor 原始程式碼。 建議您產生原始程式碼,以便能夠修改程式碼並變更行為。 例如,您可以指示 Scaffolder 產生註冊使用的程式碼。 產生的程式碼優先于 RCL 中的 Identity 相同程式碼。 若要完全控制 UI,而不使用預設 RCL,請參閱 建立完整 Identity UI 來源一節。

不包含驗證的應用程式可以套用 Scaffolder 以新增 RCL Identity 套件。 您可以選擇選取 Identity 要產生的程式碼。

雖然 Scaffolder 會產生大部分的必要程式碼,但您需要更新專案以完成程式。 本檔說明完成 Identity Scaffolding 更新所需的步驟。

建議您使用原始檔控制系統來顯示檔案差異,並可讓您回復變更。 在執行 Scaffolder 之後檢查 Identity 變更。

使用 Two Factor Authentication帳戶確認和密碼復原,以及搭配 Identity 的其他安全性功能時,需要服務。 當 Scaffolding Identity 時,不會產生服務或服務存根。 必須手動新增啟用這些功能的服務。 例如,請參閱 需要電子郵件確認

當以新的資料內容建構 Identity 成具有現有個別帳戶的專案時:

  • 在 中 Startup.ConfigureServices ,移除對下列專案發出的呼叫:
    • AddDbContext
    • AddDefaultIdentity

例如, AddDbContextAddDefaultIdentity 會在下列程式碼中加上批註:

public void ConfigureServices(IServiceCollection services)
{
    //services.AddDbContext<ApplicationDbContext>(options =>
    //    options.UseSqlServer(
    //        Configuration.GetConnectionString("DefaultConnection")));
    //services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    //    .AddEntityFrameworkStores<ApplicationDbContext>();
    services.AddControllersWithViews();
    services.AddRazorPages();
}

上述程式碼會將中重複的程式碼批註化 Areas/Identity/IdentityHostingStartup.cs

一般而言,使用個別帳戶建立的應用程式 不應該 建立新的資料內容。

將 Scaffold Identity 建置成空的專案

Identity執行 scaffolder:

  • [方案總管] 中,以滑鼠右鍵按一下專案 >[新增>Scaffolded 專案]。
  • 從 [新增 Scaffolded 專案] 對話方塊的左窗格中,選取 [ Identity>新增]。
  • 在 [新增 Identity] 對話方塊中,選取您想要的選項。
    • 選取現有的版面配置頁面,或您的版面配置檔案將會以不正確的標記覆寫:
      • ~/Pages/Shared/_Layout.cshtml 針對 Razor 頁面
      • ~/Views/Shared/_Layout.cshtml MVC 專案的
      • Blazor Server根據預設,不會針對 Razor Pages 或 MVC 設定從 Blazor Server 範本建立 (blazorserver) 的應用程式。 將版面配置頁面專案保留空白。
    • +選取按鈕以建立新的[資料] 內容類別別。 接受預設值或指定類別 (例如, MyApplication.Data.ApplicationDbContext) 。
  • 選取 [新增]。

Startup使用類似下列的程式碼更新 類別:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();
        services.AddRazorPages();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            app.UseHsts();
        }
        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
            endpoints.MapRazorPages();
        });
    }
}

UseHsts 建議使用 ,但並非必要。 如需詳細資訊,請參閱 HTTP Strict Transport Security Protocol

產生的 Identity 資料庫程式碼需要 Entity Framework Core 移轉。 建立移轉並更新資料庫。 例如,執行下列命令:

在 Visual Studio 套件管理員主控台中

Install-Package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
Add-Migration CreateIdentitySchema
Update-Database

命令的 Add-Migration 「建立 Identity 架構」名稱參數是任意的。 "CreateIdentitySchema" 描述移轉。

在沒有現有授權的情況下,將 Scaffold Identity 建置成 Razor 專案

Identity執行 scaffolder:

  • [方案總管] 中,以滑鼠右鍵按一下專案 >[新增>Scaffolded 專案]。
  • 從 [新增 Scaffolded 專案] 對話方塊的左窗格中,選取 [ Identity>新增]。
  • 在 [新增 Identity] 對話方塊中,選取您想要的選項。
    • 選取現有的版面配置頁面,或您的版面配置檔案將會以不正確的標記覆寫:
      • ~/Pages/Shared/_Layout.cshtml 針對 Razor 頁面
      • ~/Views/Shared/_Layout.cshtml MVC 專案的
      • Blazor Server根據預設,不會針對 Razor Pages 或 MVC 設定從 Blazor Server 範本建立 (blazorserver) 的應用程式。 將版面配置頁面專案保留空白。
    • +選取按鈕以建立新的[資料] 內容類別別。 接受預設值或指定類別 (例如, MyApplication.Data.ApplicationDbContext) 。
  • 選取 [新增]。

Identity 已在 中 Areas/Identity/IdentityHostingStartup.cs 設定。 如需詳細資訊,請參閱 IHostingStartup

移轉、UseAuthentication 和版面配置

產生的 Identity 資料庫程式碼需要 Entity Framework Core 移轉。 建立移轉並更新資料庫。 例如,執行下列命令:

在 Visual Studio 套件管理員主控台中

Install-Package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
Add-Migration CreateIdentitySchema
Update-Database

命令的 Add-Migration 「建立 Identity 架構」名稱參數是任意的。 "CreateIdentitySchema" 描述移轉。

啟用驗證

Startup使用類似下列的程式碼更新 類別:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorPages();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages();
        });
    }
}

UseHsts 建議使用 ,但並非必要。 如需詳細資訊,請參閱 HTTP Strict Transport Security Protocol

版面配置變更

選擇性:將登入部分 (_LoginPartial) 新增至版面配置檔案:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - WebRP</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-area="" asp-page="/Index">WebRP</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
                    <partial name="_LoginPartial" />
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2019 - WebRP - <a asp-area="" asp-page="/Privacy">Privacy</a>
        </div>
    </footer>

    <script src="~/lib/jquery/dist/jquery.min.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>

    @RenderSection("Scripts", required: false)
</body>
</html>

使用授權將 Scaffold Identity 建置成 Razor 專案

Identity執行 scaffolder:

  • [方案總管] 中,以滑鼠右鍵按一下專案 >[新增>Scaffolded 專案]。
  • 從 [ 新增 Scaffolded 專案 ] 對話方塊的左窗格中,選取 Identity 。 在中央窗格中選取 Identity 。 選取 [新增] 按鈕。
  • 在 [新增 Identity] 對話方塊中,選取您想要的選項。
    • 選取現有的版面配置頁面,讓您的版面配置檔案不會以不正確的標記覆寫。 選取現有的 _Layout.cshtml 檔案時, 不會 覆寫它。 例如:
      • ~/Pages/Shared/_Layout.cshtml適用于 Razor 具有現有 Razor Pages 基礎結構的頁面或 Blazor Server 專案。
      • ~/Views/Shared/_Layout.cshtml 適用于具有現有 MVC 基礎結構的 MVC 專案或 Blazor Server 專案。
  • 若要使用現有的資料內容,請選取至少一個要覆寫的檔案。 您必須選取至少一個檔案,才能新增資料內容。
    • 選取您的資料內容類別別。
    • 選取 [新增]。
  • 若要建立新的使用者內容,並可能建立 的 Identity 自訂使用者類別:
    • +選取按鈕以建立新的資料內容類別別。 接受預設值,或指定類別 (例如, MyApplication.Data.ApplicationDbContext) 。
    • 選取 [新增]。

注意:如果您要建立新的使用者內容,就不需要選取要覆寫的檔案。

Identity執行 Scaffolder:

  • [方案總管]中,以滑鼠右鍵按一下專案 >[新增>Scaffolded 專案]。
  • 從 [新增 Scaffold] 對話方塊的左窗格中,選取 [ Identity>新增]。
  • 在 [新增 Identity] 對話方塊中,選取您想要的選項。
    • 選取現有的版面配置頁面,讓您的版面配置檔案不會以不正確的標記覆寫。 選取現有的 _Layout.cshtml 檔案時, 不會 覆寫它。 例如:
      • ~/Pages/Shared/_Layout.cshtml適用于 Razor 具有現有 Razor Pages 基礎結構的頁面或 Blazor Server 專案
      • ~/Views/Shared/_Layout.cshtml 適用于具有現有 MVC 基礎結構的 MVC 專案或 Blazor Server 專案
  • 若要使用現有的資料內容,請選取至少一個要覆寫的檔案。 您必須選取至少一個檔案,才能新增資料內容。
    • 選取您的資料內容類別別。
    • 選取 [新增]。
  • 若要建立新的使用者內容,並可能建立 的 Identity 自訂使用者類別:
    • +選取按鈕以建立新的資料內容類別別。 接受預設值,或指定類別 (例如, MyApplication.Data.ApplicationDbContext) 。
    • 選取 [新增]。

注意:如果您要建立新的使用者內容,就不需要選取要覆寫的檔案。

某些 Identity 選項是在 中 Areas/Identity/IdentityHostingStartup.cs 設定。 如需詳細資訊,請參閱 IHostingStartup

在沒有現有授權的情況下,Scaffold Identity 進入 MVC 專案

Identity執行 Scaffolder:

  • [方案總管]中,以滑鼠右鍵按一下專案 >[新增>Scaffolded 專案]。
  • 從 [新增 Scaffolded 專案] 對話方塊的左窗格中,選取 [ Identity>新增]。
  • 在 [新增 Identity] 對話方塊中,選取您想要的選項。
    • 選取現有的版面配置頁面,或您的版面配置檔案將會以不正確的標記覆寫:
      • ~/Pages/Shared/_Layout.cshtml 針對 Razor 頁面
      • ~/Views/Shared/_Layout.cshtml 針對 MVC 專案
      • Blazor Server 根據預設,不會針對 Pages 或 MVC 設定從 Blazor Server 範本 (blazorserver) 建立 Razor 的應用程式。 將版面配置頁面專案保留空白。
    • +選取按鈕以建立新的資料內容類別別。 接受預設值,或指定類別 (例如, MyApplication.Data.ApplicationDbContext) 。
  • 選取 [新增]。

選擇性:將登入部分 () _LoginPartial 新增至 Views/Shared/_Layout.cshtml 檔案:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - WebRP</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-area="" asp-page="/Index">WebRP</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
                    <partial name="_LoginPartial" />
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2019 - WebRP - <a asp-area="" asp-page="/Privacy">Privacy</a>
        </div>
    </footer>

    <script src="~/lib/jquery/dist/jquery.min.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>

    @RenderSection("Scripts", required: false)
</body>
</html>
  • Pages/Shared/_LoginPartial.cshtml 檔案移至 Views/Shared/_LoginPartial.cshtml

Identity 已在 中 Areas/Identity/IdentityHostingStartup.cs 設定。 如需詳細資訊,請參閱 IHostingStartup。

產生的 Identity 資料庫程式碼需要 Entity Framework Core 移轉。 建立移轉並更新資料庫。 例如,執行下列命令:

在 Visual Studio 套件管理員主控台中:

Install-Package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
Add-Migration CreateIdentitySchema
Update-Database

命令的 Add-Migration 「建立 Identity 架構」名稱參數是任意的。 "CreateIdentitySchema" 描述移轉。

Startup使用類似下列的程式碼更新 類別:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();
        services.AddRazorPages();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            app.UseHsts();
        }
        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
            endpoints.MapRazorPages();
        });
    }
}

UseHsts 建議使用,但並非必要。 如需詳細資訊,請參閱 HTTP Strict Transport Security Protocol

使用授權將 Scaffold Identity 建置成 MVC 專案

Identity執行 scaffolder:

  • [方案總管] 中,以滑鼠右鍵按一下專案 >[新增>Scaffolded 專案]。
  • 從 [ 新增 Scaffolded 專案 ] 對話方塊的左窗格中,選取 Identity 。 在中央窗格中選取 Identity 。 選取 [新增] 按鈕。
  • 在 [新增 Identity] 對話方塊中,選取您想要的選項。
    • 選取現有的版面配置頁面,讓版面配置檔案不會以不正確的標記覆寫。 選取現有的 _Layout.cshtml 檔案時, 不會 覆寫它。 例如:
      • ~/Pages/Shared/_Layout.cshtml適用于 Razor 具有現有 Razor Pages 基礎結構的頁面或 Blazor Server 專案。
      • ~/Views/Shared/_Layout.cshtml 適用于具有現有 MVC 基礎結構的 MVC 專案或 Blazor Server 專案。
  • 若要使用現有的資料內容,請選取至少一個要覆寫的檔案。 您必須選取至少一個檔案以新增資料內容。
    • 選取您的資料內容類別別。
    • 選取 [新增]。
  • 若要建立新的使用者內容,並可能為 Identity 建立自訂使用者類別:
    • +選取按鈕以建立新的[資料] 內容類別別。 接受預設值或指定類別 (例如, MyApplication.Data.ApplicationDbContext) 。
    • 選取 [新增]。

注意:如果您要建立新的使用者內容,則不需要選取要覆寫的檔案。

Identity執行 scaffolder:

  • [方案總管] 中,以滑鼠右鍵按一下專案 >[新增>Scaffolded 專案]。
  • 從 [新增 Scaffold]對話方塊的左窗格中,選取 [ Identity>新增]。
  • 在 [新增 Identity] 對話方塊中,選取您想要的選項。
    • 選取現有的版面配置頁面,讓版面配置檔案不會以不正確的標記覆寫。 選取現有的 _Layout.cshtml 檔案時, 不會 覆寫它。 例如:
      • ~/Pages/Shared/_Layout.cshtml適用于 Razor 具有現有 Razor Pages 基礎結構的頁面或 Blazor Server 專案
      • ~/Views/Shared/_Layout.cshtml 適用于具有現有 MVC 基礎結構的 MVC 專案或 Blazor Server 專案
  • 若要使用現有的資料內容,請選取至少一個要覆寫的檔案。 您必須選取至少一個檔案以新增資料內容。
    • 選取您的資料內容類別別。
    • 選取 [新增]。
  • 若要建立新的使用者內容,並可能為 Identity 建立自訂使用者類別:
    • +選取按鈕以建立新的[資料] 內容類別別。 接受預設值或指定類別 (例如, MyApplication.Data.ApplicationDbContext) 。
    • 選取 [新增]。

注意:如果您要建立新的使用者內容,則不需要選取要覆寫的檔案。

在沒有現有授權的情況下,將 Scaffold Identity 建置成 Blazor Server 專案

Identity執行 scaffolder:

  • [方案總管] 中,以滑鼠右鍵按一下專案 >[新增>Scaffolded 專案]。
  • 從 [新增 Scaffolded 專案] 對話方塊的左窗格中,選取 [ Identity>新增]。
  • 在 [新增 Identity] 對話方塊中,選取您想要的選項。
    • 選取現有的版面配置頁面,或您的版面配置檔案將會以不正確的標記覆寫:
      • ~/Pages/Shared/_Layout.cshtml 針對 Razor 頁面
      • ~/Views/Shared/_Layout.cshtml MVC 專案的
      • Blazor Server根據預設,不會針對 Razor Pages 或 MVC 設定從 Blazor Server 範本建立 (blazorserver) 的應用程式。 將版面配置頁面專案保留空白。
    • +選取按鈕以建立新的[資料] 內容類別別。 接受預設值或指定類別 (例如, MyApplication.Data.ApplicationDbContext) 。
  • 選取 [新增]。

Identity 已在 中 Areas/Identity/IdentityHostingStartup.cs 設定。 如需詳細資訊,請參閱 IHostingStartup

移轉

產生的 Identity 資料庫程式碼需要 Entity Framework Core 移轉。 建立移轉並更新資料庫。 例如,執行下列命令:

在 Visual Studio 套件管理員主控台中:

Install-Package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
Add-Migration CreateIdentitySchema
Update-Database

命令的 Add-Migration 「建立 Identity 架構」名稱參數是任意的。 "CreateIdentitySchema" 描述移轉。

將 XSRF 權杖傳遞至應用程式

權杖可以傳遞至元件:

  • 將驗證權杖布建並儲存至驗證 cookie 時,可以傳遞至元件。
  • Razor 元件無法直接使用 HttpContext ,因此無法取得 反要求偽造 (XSRF) 權杖 至 POST 的 Identity 登出端點 /Identity/Account/Logout 。 XSRF 權杖可以傳遞至元件。

如需詳細資訊,請參閱 ASP.NET 核心 Blazor Server 其他安全性案例

在 檔案中 Pages/_Host.cshtml ,在將權杖新增至 InitialApplicationStateTokenProvider 類別之後建立權杖:

@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf

...

var tokens = new InitialApplicationState
{
    ...

    XsrfToken = Xsrf.GetAndStoreTokens(HttpContext).RequestToken
};

更新元件 App (App.razor) 以指派 InitialState.XsrfToken

@inject TokenProvider TokenProvider

...

TokenProvider.XsrfToken = InitialState.XsrfToken;

TokenProvider本主題中示範的服務會用於 LoginDisplay 下列版面配置和驗證流程變更一節中的元件。

啟用驗證

在 類別中 Startup

  • 確認 Razor 已在 中 Startup.ConfigureServices 新增 Pages 服務。
  • 如果使用 TokenProvider,請註冊服務。
  • UseDatabaseErrorPage在 中 Startup.Configure 針對開發環境呼叫應用程式產生器。
  • 呼叫 UseAuthenticationUseAuthorization 之後 UseRouting
  • 新增 Pages 的 Razor 端點。
public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();
    services.AddServerSideBlazor();
    services.AddSingleton<WeatherForecastService>();
    services.AddScoped<TokenProvider>();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToPage("/_Host");
    });
}

UseHsts 建議使用,但並非必要。 如需詳細資訊,請參閱 HTTP Strict Transport Security Protocol

版面配置和驗證流程變更

RedirectToLogin將元件 (RedirectToLogin.razor) 新增至專案根目錄中應用程式的共用資料夾

@inject NavigationManager Navigation
@code {
    protected override void OnInitialized()
    {
        Navigation.NavigateTo("Identity/Account/Login?returnUrl=" +
            Uri.EscapeDataString(Navigation.Uri), true);
    }
}

LoginDisplay將元件 () LoginDisplay.razor 新增至應用程式的共用資料夾TokenProvider 服務會為 POST 登出 Identity 端點的 HTML 表單提供 XSRF 權杖:

@using Microsoft.AspNetCore.Components.Authorization
@inject NavigationManager Navigation
@inject TokenProvider TokenProvider

<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" 
                value="@TokenProvider.XsrfToken">
        </form>
    </Authorized>
    <NotAuthorized>
        <a href="Identity/Account/Register">Register</a>
        <a href="Identity/Account/Login">Login</a>
    </NotAuthorized>
</AuthorizeView>

MainLayout 元件 (Shared/MainLayout.razor) 中,將 LoginDisplay 元件新增至頂端資料列 <div> 元素的內容:

<div class="top-row px-4 auth">
    <LoginDisplay />
    <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
</div>

樣式驗證端點

由於 Blazor Server 使用 Razor Pages Identity 頁面,因此當訪客在頁面和元件之間 Identity 巡覽時,UI 的樣式會變更。 您有兩個選項可解決不一致樣式:

建置 Identity 元件

使用 元件而非 Identity 頁面的方法,就是建置 Identity 元件。 由於 SignInManager 元件不支援 Razor 和 UserManager ,因此請在應用程式中使用 API 端點 Blazor Server 來處理使用者帳戶動作。

搭配 Blazor 應用程式樣式使用自訂版面配置

Identity您可以修改頁面版面配置和樣式,以產生使用預設 Blazor 主題的頁面。

注意

本節中的範例只是自訂的起點。 可能需要額外的工作,才能獲得最佳使用者體驗。

建立新的 NavMenu_IdentityLayout 元件 (Shared/NavMenu_IdentityLayout.razor) 。 針對元件的標記和程式碼,請使用應用程式 NavMenu 元件 Shared/NavMenu.razor () 相同的內容。 移除任何 NavLink 無法匿名連線的元件,因為元件中的 RedirectToLogin 自動重新導向失敗,因為需要驗證或授權的元件。

在 檔案中 Pages/Shared/Layout.cshtml ,進行下列變更:

  • 將指示詞新增 Razor 至檔案頂端,以在 共用資料夾 中使用標籤協助程式和應用程式的元件:

    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    @using {APPLICATION ASSEMBLY}.Shared
    

    將 取代 {APPLICATION ASSEMBLY} 為應用程式的元件名稱。

  • <base>將標籤和 Blazor 樣式表單 <link> 新增至 <head> 內容:

    <base href="~/" />
    <link rel="stylesheet" href="~/css/site.css" />
    
  • 將標籤的內容 <body> 變更為下列內容:

    <div class="sidebar" style="float:left">
        <component type="typeof(NavMenu_IdentityLayout)" 
            render-mode="ServerPrerendered" />
    </div>
    
    <div class="main" style="padding-left:250px">
        <div class="top-row px-4">
            @{
                var result = Engine.FindView(ViewContext, "_LoginPartial", 
                    isMainPage: false);
            }
            @if (result.Success)
            {
                await Html.RenderPartialAsync("_LoginPartial");
            }
            else
            {
                throw new InvalidOperationException("The default Identity UI " +
                    "layout requires a partial view '_LoginPartial'.");
            }
            <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
        </div>
    
        <div class="content px-4">
            @RenderBody()
        </div>
    </div>
    
    <script src="~/Identity/lib/jquery/dist/jquery.min.js"></script>
    <script src="~/Identity/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
    <script src="~/Identity/js/site.js" asp-append-version="true"></script>
    @RenderSection("Scripts", required: false)
    <script src="_framework/blazor.server.js"></script>
    

使用授權將 Scaffold Identity 建置成 Blazor Server 專案

Identity執行 Scaffolder:

  • [方案總管]中,以滑鼠右鍵按一下專案 >[新增>Scaffolded 專案]。
  • 從 [ 新增 Scaffolded 專案 ] 對話方塊的左窗格中,選取 Identity 。 在中央窗格中選取 Identity 。 選取 [新增] 按鈕。
  • 在 [新增 Identity] 對話方塊中,選取您想要的選項。
    • 選取現有的版面配置頁面,讓您的版面配置檔案不會以不正確的標記覆寫。 選取現有的 _Layout.cshtml 檔案時, 不會 覆寫它。 例如:
      • ~/Pages/Shared/_Layout.cshtml適用于 Razor 具有現有 Razor Pages 基礎結構的頁面或 Blazor Server 專案。
      • ~/Views/Shared/_Layout.cshtml 適用于具有現有 MVC 基礎結構的 MVC 專案或 Blazor Server 專案。
  • 若要使用現有的資料內容,請選取至少一個要覆寫的檔案。 您必須選取至少一個檔案,才能新增資料內容。
    • 選取您的資料內容類別別。
    • 選取 [新增]。
  • 若要建立新的使用者內容,並可能建立 的 Identity 自訂使用者類別:
    • +選取按鈕以建立新的資料內容類別別。 接受預設值,或指定類別 (例如, MyApplication.Data.ApplicationDbContext) 。
    • 選取 [新增]。

注意:如果您要建立新的使用者內容,就不需要選取要覆寫的檔案。

Identity執行 Scaffolder:

  • [方案總管]中,以滑鼠右鍵按一下專案 >[新增>Scaffolded 專案]。
  • 從 [新增 Scaffold] 對話方塊的左窗格中,選取 [ Identity>新增]。
  • 在 [新增 Identity] 對話方塊中,選取您想要的選項。
    • 選取現有的版面配置頁面,讓您的版面配置檔案不會以不正確的標記覆寫。 選取現有的 _Layout.cshtml 檔案時, 不會 覆寫它。 例如:
      • ~/Pages/Shared/_Layout.cshtml適用于 Razor 具有現有 Razor Pages 基礎結構的頁面或 Blazor Server 專案
      • ~/Views/Shared/_Layout.cshtml 適用于具有現有 MVC 基礎結構的 MVC 專案或 Blazor Server 專案
  • 若要使用現有的資料內容,請選取至少一個要覆寫的檔案。 您必須選取至少一個檔案,才能新增資料內容。
    • 選取您的資料內容類別別。
    • 選取 [新增]。
  • 若要建立新的使用者內容,並可能建立 的 Identity 自訂使用者類別:
    • +選取按鈕以建立新的資料內容類別別。 接受預設值,或指定類別 (例如, MyApplication.Data.ApplicationDbContext) 。
    • 選取 [新增]。

注意:如果您要建立新的使用者內容,則不需要選取要覆寫的檔案。

某些 Identity 選項是在 中 Areas/Identity/IdentityHostingStartup.cs 設定。 如需詳細資訊,請參閱 IHostingStartup

獨立或託管 Blazor WebAssembly 的應用程式

Blazor WebAssembly用戶端應用程式會使用自己的 Identity UI 方法,而且無法使用 ASP.NET Core Identity Scaffolding。 裝載解決方案的 Blazor 伺服器端 ASP.NET 核心應用程式可以遵循 Razor 本文中的 Pages/MVC 指引,而且設定方式就像支援 的任何其他 ASP.NET Core 應用程式 Identity 類型一樣。

架構 Blazor 不包含 Razor UI 頁面的 Identity 元件版本。 Identity UI Razor 元件可以自訂建置或從不支援的協力廠商來源取得。

如需詳細資訊,請參閱Blazor 安全性和 Identity 文章

建立完整的 Identity UI 來源

若要維持 UI 的完整控制權 Identity ,請 Identity 執行 Scaffolder 並選取 [覆寫所有檔案]。

下列醒目提示的程式碼顯示將預設 Identity UI Identity 取代為 ASP.NET Core 2.1 Web 應用程式中的變更。 您可能想要這麼做,以完全控制 Identity UI。

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });

    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection")));

    services.AddIdentity<IdentityUser, IdentityRole>()
        // services.AddDefaultIdentity<IdentityUser>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

    services.AddMvc()
        .AddRazorPagesOptions(options =>
        {
            options.Conventions.AuthorizeAreaFolder("Identity", "/Account/Manage");
            options.Conventions.AuthorizeAreaPage("Identity", "/Account/Logout");
        });

    services.ConfigureApplicationCookie(options =>
    {
        options.LoginPath = $"/Identity/Account/Login";
        options.LogoutPath = $"/Identity/Account/Logout";
        options.AccessDeniedPath = $"/Identity/Account/AccessDenied";
    });

    // using Microsoft.AspNetCore.Identity.UI.Services;
    services.AddSingleton<IEmailSender, EmailSender>();
}

預設 Identity 會在下列程式碼中取代:

services.AddIdentity<IdentityUser, IdentityRole>()
    // services.AddDefaultIdentity<IdentityUser>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

下列程式碼會 LoginPath 設定 、 LogoutPathAccessDeniedPath) :

services.ConfigureApplicationCookie(options =>
{
    options.LoginPath = $"/Identity/Account/Login";
    options.LogoutPath = $"/Identity/Account/Logout";
    options.AccessDeniedPath = $"/Identity/Account/AccessDenied";
});

註冊實作 IEmailSender ,例如:

// using Microsoft.AspNetCore.Identity.UI.Services;
services.AddSingleton<IEmailSender, EmailSender>();
public class EmailSender : IEmailSender
{
    public Task SendEmailAsync(string email, string subject, string message)
    {
        return Task.CompletedTask;
    }
}

密碼設定

如果在 PasswordOptionsStartup.ConfigureServices 設定 ,[StringLength]Password Scaffold 頁面 Identity 的 屬性可能需要屬性組態。 InputModelPassword 屬性位於下列檔案中:

  • Areas/Identity/Pages/Account/Register.cshtml.cs
  • Areas/Identity/Pages/Account/ResetPassword.cshtml.cs

停用頁面

本節說明如何停用註冊頁面,但方法可用來停用任何頁面。

若要停用使用者註冊:

  • Scaffold Identity 。 包含 Account.Register、Account.Login 和 Account.RegisterConfirmation。 例如:

    dotnet aspnet-codegenerator identity -dc RPauth.Data.ApplicationDbContext --files "Account.Register;Account.Login;Account.RegisterConfirmation"
    
  • 更新 Areas/Identity/Pages/Account/Register.cshtml.cs ,讓使用者無法從此端點註冊:

    public class RegisterModel : PageModel
    {
        public IActionResult OnGet()
        {
            return RedirectToPage("Login");
        }
    
        public IActionResult OnPost()
        {
            return RedirectToPage("Login");
        }
    }
    
  • 更新 Areas/Identity/Pages/Account/Register.cshtml 以與上述變更一致:

    @page
    @model RegisterModel
    @{
        ViewData["Title"] = "Go to Login";
    }
    
    <h1>@ViewData["Title"]</h1>
    
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Login">Login</a>
    </li>
    
  • 批註化或移除註冊連結 Areas/Identity/Pages/Account/Login.cshtml

    @*
    <p>
        <a asp-page="./Register" asp-route-returnUrl="@Model.ReturnUrl">Register as a new user</a>
    </p>
    *@
    
  • 更新 [區域/ Identity /頁面/帳戶/RegisterConfirmation ] 頁面。

    • 從 cshtml 檔案中移除程式碼和連結。
    • PageModel 移除確認碼:
    [AllowAnonymous]
      public class RegisterConfirmationModel : PageModel
      {
          public IActionResult OnGet()
          {  
              return Page();
          }
      }
    

使用另一個應用程式新增使用者

提供在 Web 應用程式外部新增使用者的機制。 新增使用者的選項包括:

  • 專用的管理 Web 應用程式。
  • 主控台應用程式。

下列程式碼概述新增使用者的一種方法:

  • 使用者清單會讀入記憶體中。
  • 每個使用者都會產生強式唯一密碼。
  • 使用者會新增至 Identity 資料庫。
  • 系統會通知使用者,並告知使用者變更密碼。
public class Program
{
    public static void Main(string[] args)
    {
        var host = CreateHostBuilder(args).Build();

        using (var scope = host.Services.CreateScope())
        {
            var services = scope.ServiceProvider;

            try
            {
                var context = services.GetRequiredService<AppDbCntx>();
                context.Database.Migrate();

                var config = host.Services.GetRequiredService<IConfiguration>();
                var userList = config.GetSection("userList").Get<List<string>>();

                SeedData.Initialize(services, userList).Wait();
            }
            catch (Exception ex)
            {
                var logger = services.GetRequiredService<ILogger<Program>>();
                logger.LogError(ex, "An error occurred adding users.");
            }
        }

        host.Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

下列程式碼概述新增使用者:


public static async Task Initialize(IServiceProvider serviceProvider,
                                    List<string> userList)
{
    var userManager = serviceProvider.GetService<UserManager<IdentityUser>>();

    foreach (var userName in userList)
    {
        var userPassword = GenerateSecurePassword();
        var userId = await EnsureUser(userManager, userName, userPassword);

        NotifyUser(userName, userPassword);
    }
}

private static async Task<string> EnsureUser(UserManager<IdentityUser> userManager,
                                             string userName, string userPassword)
{
    var user = await userManager.FindByNameAsync(userName);

    if (user == null)
    {
        user = new IdentityUser(userName)
        {
            EmailConfirmed = true
        };
        await userManager.CreateAsync(user, userPassword);
    }

    return user.Id;
}

針對生產案例,可以遵循類似的方法。

防止發佈靜態 Identity 資產

若要防止將靜態 Identity 資產發佈至 Web 根目錄,請參閱 Identity ASP.NET Core 簡介

其他資源