一、做好准备

ASP.NET Core Identity 是 ASP.NET Core 应用的用户管理系统。它提供了一个 API 来管理用户和角色,以及让用户登录和退出应用。用户可以使用简单的密码登录,使用双重认证,或者使用谷歌、脸书和 Twitter 提供的第三方平台登录。

在本书中,我解释了 ASP.NET Core Identity 是如何使用的,以及它是如何在幕后工作的。我描述了内置特性,从可用于简单应用的特性到高级项目的深度定制。

你需要知道什么?

这是一本为有经验的开发人员编写的高级书籍。除非你熟悉使用 ASP.NET Core 的 web 开发,否则你不应该尝试阅读这本书。你必须理解 HTML 以及它是如何使用 Razor 页面和 MVC 框架产生的。您必须至少对应用安全性有一个基本的了解,尽管我在解释 ASP.NET Core Identity 如何实现它们时会介绍一些关键概念。

这本书的结构是什么?

这本书分为两部分,每一部分都涵盖了一系列相关的主题。

第 1 部分:使用 ASP.NET Core 标识

在本书的第 1 部分,我将向您展示如何将 ASP.NET Core Identity 应用到 ASP.NET Core 项目中。我将向您展示如何设置和配置 Identity,如何使用内置的 Identity UI 包来管理用户帐户,以及如何使用 API 来创建自定义工作流。在本书的这一部分结束时,你将准备好在你的项目中使用 ASP.NET Core Identity。

第 2 部分:了解 ASP.NET Core

在本书的第 2 部分中,我深入探讨了细节,并解释了第 1 部分中使用的特性是如何实现的,如何对它们进行定制,以及它们如何与 ASP.NET Core 平台提供的特性相关联。在本书的这一部分结束时,您将准备好创建定制的接口实现,这些接口塑造了 ASP.NET Core Identity,以满足最先进的 ASP.NET Core 项目的需求。

这本书没有涵盖什么?

如上所述,这本书是为有经验的 ASP.NET Core 开发人员编写的,他们希望了解 ASP.NET Core Identity 并将其应用到他们的 ASP.NET Core 项目中。它没有解释 web 应用或编程的基础知识。它没有描述 ASP.NET Core 平台,除了它与 Identity 如何工作有关。

我涵盖了大多数面向互联网的 ASP.NET Core 项目所使用的认证场景。我不描述与 ASP.NET Core Identity 不直接相关的 ASP.NET Core Identity 认证功能,如与 Active Directory 或第三方产品(如 IdentityServer)的集成(尽管其名称与 ASP.NET Core Identity 没有直接关系,更多的是一种替代方案)。

对于这些例子,我需要什么软件?

您需要与 ASP.NET Core 开发相同的工具集,包括。NET SDK 和 Visual Studio 或 Visual Studio 代码。我在第 2 章中描述了本书所需的设置。

我如何设置开发环境?

2 章通过创建一个简单的应用来介绍 ASP.NET Core Identity,并且,作为该过程的一部分,我将告诉您如何按照本书中的示例创建一个开发环境。

如果我对这些例子有疑问怎么办?

首先要做的是回到这一章的开头,重新开始。大多数问题都是由于意外跳过某个步骤或者没有完全应用清单中显示的更改而导致的。请密切注意代码清单中的重点,它突出了需要进行的更改。

接下来,查看勘误表/更正表,它包含在本书的 GitHub 资源库中。尽管我和我的编辑尽了最大的努力,技术书籍还是很复杂,错误是不可避免的。请查看勘误表,了解已知错误列表以及解决这些错误的说明。

如果您仍然有问题,那么从本书的 GitHub 资源库 https://github.com/Apress/pro-asp.net-core-identity 下载您正在阅读的章节的项目,并将其与您的项目进行比较。我通过阅读每一章来创建 GitHub 存储库的代码,所以您的项目中应该有相同内容的相同文件。

如果你仍然不能让例子工作,那么你可以联系我在adam@adam-freeman.com寻求帮助。请在邮件中明确你在看哪本书,哪个章节/例子导致了这个问题。页码或代码列表总是有用的。请记住,我收到很多电子邮件,我可能不会立即回复。

第 11 章、第 22 章第 23 章中有依赖于来自谷歌、脸书和推特的第三方服务的例子。我无法为这些示例提供支持,因为只能使用您的私人帐户凭据来诊断问题。就算你愿意分享你的凭据,我也不愿意用。如果您对这些示例有疑问,您应该向认证服务提供商提出支持查询。

如果我发现书中有错误怎么办?

您可以在adam@adam-freeman.com通过电子邮件向我报告错误,尽管我要求您首先检查这本书的勘误表/更正列表,您可以在本书的 GitHub 资源库 https://github.com/Apress/pro-asp.net-core-identity 中找到,以防它已经被报告。

我在 GitHub 资源库的勘误表/更正文件中列出了可能会让读者困惑的错误,尤其是示例代码的问题,并对第一个报告该问题的读者表示感谢。我保留了一个不太严重的问题的列表,这通常意味着例子周围的文本中的错误,当我编写新版本时,我会纠正它们。

有很多例子吗?

个载荷的例子。最好的学习方法是通过例子,我已经尽可能多的把它们放进了这本书里。为了让例子更容易理解,我采用了一个简单的约定,只要有可能,我都会遵守。当我创建一个新文件时,我会列出完整的内容,如清单 1-1 所示。所有代码清单都在清单头中包含文件的名称,以及可以找到它的文件夹。

@page "{id?}"
@model IdentityApp.Pages.Identity.Admin.DeleteModel
@{
    ViewBag.Workflow = "Delete";
}

<div asp-validation-summary="All" class="text-danger m-2"></div>

<form method="post">

    <h3 class="bg-danger text-white text-center p-2">Caution</h3>

    <h5 class="text-center m-2">
        Delete @Model.IdentityUser.Email?
    </h5>
    <input type="hidden" name="id" value="@Model.IdentityUser.Id" />
    <div class="text-center p-2">
        <button type="submit" class="btn btn-danger">Delete</button>
        <a asp-page="Dashboard" class="btn btn-secondary">Cancel</a>
    </div>
</form>

Listing 1-1.The Contents of the Delete.cshtml File in the Pages/Identity/Admin Folder

该列表摘自第 9 章。不要担心它做什么;请注意,这是一个完整的列表,它显示了文件的全部内容,文件头告诉您文件的名称及其在项目中的位置。

当我修改代码时,我用粗体显示修改后的语句,如清单 1-2 所示。

@page "{id?}"
@model IdentityApp.Pages.Identity.Admin.DeleteModel
@inject Microsoft.Extensions.Configuration.IConfiguration Configuration
@{
    ViewBag.Workflow = "Delete";
    string dashboardUser = Configuration["Dashboard:User"] ?? "admin@example.com";
}

<div asp-validation-summary="All" class="text-danger m-2"></div>

<form method="post">
    <h3 class="bg-danger text-white text-center p-2">Caution</h3>
    <h5 class="text-center m-2">
        Delete @Model.IdentityUser.Email?
    </h5>
    <input type="hidden" name="id" value="@Model.IdentityUser.Id" />
    <div class="text-center p-2">
        <button type="submit" class="btn btn-danger"
            disabled="@(Model.IdentityUser.Email == dashboardUser)">
                Delete
        </button>
        <a asp-page="Dashboard" class="btn btn-secondary">Cancel</a>
    </div>
</form>

Listing 1-2.Disabling a Button in the Delete.cshtml File in the Pages/Identity/Admin Folder

这个清单取自后面的例子,它需要对清单 1-1 中创建的文件进行修改。为了帮助您遵循示例,更改用粗体标出。

一些例子需要对一个大文件做一些小的改动。为了不浪费空间列出文件中没有变化的部分,我只显示了发生变化的区域,如清单 1-3 所示。您可以看出这个清单只显示了文件的一部分,因为它以省略号(...)开始和结束。

...
public void OnGet() {
    UsersCount = UserManager.Users.Count();
    UsersUnconfirmed = UserManager.Users
        .Where(u => !u.EmailConfirmed).Count();
    UsersLockedout = UserManager.Users
        .Where(u => u.LockoutEnabled && u.LockoutEnd > System.DateTimeOffset.Now)
        .Count();
    UsersTwoFactor = UserManager.Users.Where(u => u.TwoFactorEnabled).Count();
}
...

Listing 1-3.Counting Users in the Dashboard.cshtml.cs File in the Pages/Identity/Admin Folder

在某些情况下,我需要对同一个文件的不同部分进行修改,在这种情况下,为了简洁起见,我省略了一些元素或语句,如清单 1-4 所示。这个清单添加了新的using语句,并为一个现有文件定义了额外的方法,其中大部分没有改变,清单中已经省略了。

using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using SignInResult = Microsoft.AspNetCore.Identity.SignInResult;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authentication;
using System.Net;

namespace IdentityApp.Pages.Identity {

    [AllowAnonymous]
    public class SignInModel : UserPageModel {

        // ...methods and properties omitted for brevity...

        public IActionResult OnPostExternalAsync(string provider) {
            string callbackUrl = Url.Page("SignIn", "Callback", new { ReturnUrl });
            AuthenticationProperties props =
               SignInManager.ConfigureExternalAuthenticationProperties(
                   provider, callbackUrl);
            return new ChallengeResult(provider, props);
        }

        public async Task<IActionResult> OnGetCallbackAsync() {
            ExternalLoginInfo info = await SignInManager.GetExternalLoginInfoAsync();
            SignInResult result = await SignInManager.ExternalLoginSignInAsync(
                info.LoginProvider, info.ProviderKey, true);
            if (result.Succeeded) {
                return Redirect(WebUtility.UrlDecode(ReturnUrl ?? "/"));
            } else if (result.IsLockedOut) {
                TempData["message"] = "Account Locked";
            } else if (result.IsNotAllowed) {
                TempData["message"] = "Sign In Not Allowed";
            } else {
                TempData["message"] = "Sign In Failed";
            }
            return RedirectToPage();
        }
    }
}

Listing 1-4.Supporting External Services in the SignIn.cshtml.cs File in the Pages/Identity Folder

这种约定让我可以提供更多的例子,但是这确实意味着很难找到一种特定的技术。为此,本书中的章节以一个描述其包含的技术的汇总表开始,第 1 部分中的许多章节包含快速参考表,这些表列出了用于实现特定特性的方法。

从哪里可以获得示例代码?

你可以从 https://github.com/Apress/pro-asp.net-core-identity 下载本书所有章节的范例项目。

我如何联系作者?

你可以在adam@adam-freeman.com给我发邮件。自从我第一次在我的书中发表电子邮件地址已经有几年了。我不能完全肯定这是一个好主意,但我很高兴我这样做了。我收到了来自世界各地的电子邮件,来自各行各业工作或学习的读者,无论如何,在大多数情况下,这些电子邮件都是积极的,礼貌的,并且很高兴收到。

我试图及时回复,但我会收到许多电子邮件,有时会积压大量邮件,尤其是当我低着头试图写完一本书时。我总是试图帮助那些被书中的一个例子困住的读者,尽管我要求你在联系我之前按照本章前面描述的步骤去做。

虽然我欢迎读者的电子邮件,但有一些常见问题的答案永远是“不”。我担心我不会为你的新公司编写代码,不会帮助你完成大学作业,不会参与你的开发团队的设计争议,也不会教你如何编程。

如果我真的喜欢这本书呢?

请发电子邮件到adam@adam-freeman.com告诉我。收到一个快乐的读者的来信总是一件令人高兴的事,我很感激花时间发送这些邮件。写这些书可能很难,而这些邮件为坚持一项有时感觉不可能的活动提供了必要的动力。

如果这本书让我生气了,我想投诉怎么办?

你仍然可以在adam@adam-freeman.com给我发邮件,我仍然会尽力帮助你。请记住,只有当你解释了问题是什么,以及你希望我做些什么时,我才能提供帮助。你应该明白,有时唯一的结果是接受我不是你的作者,只有当你归还这本书并选择另一本时,我们才会结束。我会仔细考虑让你心烦意乱的事情,但是经过 25 年的写书生涯,我已经接受了不是每个人都喜欢读我喜欢写的书。

摘要

在这一章中,我概述了这本书的内容和结构。学习 ASP.NET Core Identity 的最好方法是通过实例,所以在下一章,我将直接向您展示如何设置您的开发环境,并使用它来创建您的第一个 ASP.NET Core Identity 项目。