练习 - 配置多重身份验证

已完成

在上一单元中,你了解了 ASP.NET Core 标识如何为多重身份验证 (MFA) 实现基于时间的一次性密码 (TOTP)。 在本单元中,将自定义现有的“配置验证器应用”表单以提供包含注册密钥的 QR 码。

生成 QR 码

存在生成 QR 码的多种策略。 文档中的示例使用客户端 JavaScript 库。 但是,在本单元中,第三方 NuGet 包用于通过 C# 在服务器上生成 QR 码。 生成的 QR 码图像以 base-64 编码字符串的形式注入 HTML 占位符元素。

“添加 QR 码”服务

让我们生成在“配置验证器应用”窗体上生成 QR 码所需的一切。

  1. 在终端窗格中,安装 QRCoder NuGet 包:

    dotnet add package QRCoder --version 1.4.3
    
  2. 在“资源管理器”窗格中,右键单击“服务”文件夹,并添加名为 QRCodeService.cs 的新文件。 添加以下代码:

    using QRCoder;
    
    namespace RazorPagesPizza.Services;
    public class QRCodeService
    {
        private readonly QRCodeGenerator _generator;
    
        public QRCodeService(QRCodeGenerator generator)
        {
            _generator = generator;
        }
    
        public string GetQRCodeAsBase64(string textToEncode)
        {
            QRCodeData qrCodeData = _generator.CreateQrCode(textToEncode, QRCodeGenerator.ECCLevel.Q);
            var qrCode = new PngByteQRCode(qrCodeData);
    
            return Convert.ToBase64String(qrCode.GetGraphic(4));
        }
    }
    

    前面的代码:

    • 使用构造函数注入访问库的 QRCodeGenerator 类的实例。
    • 公开 GetQRCodeAsBase64 方法以返回 base-64 编码字符串。 QR 码维度由传递给 GetGraphic 的整数值确定。 在此情况下,生成的 QR 码由大小为四个像素的块组成。
  3. 在 Program.cs 中,添加突出显示的行:

    using Microsoft.AspNetCore.Identity;
    using Microsoft.EntityFrameworkCore;
    using RazorPagesPizza.Areas.Identity.Data;
    using Microsoft.AspNetCore.Identity.UI.Services;
    using RazorPagesPizza.Services;
    using QRCoder;
    
    var builder = WebApplication.CreateBuilder(args);
    var connectionString = builder.Configuration.GetConnectionString("RazorPagesPizzaAuthConnection");
    builder.Services.AddDbContext<RazorPagesPizzaAuth>(options => options.UseSqlServer(connectionString)); 
    builder.Services.AddDefaultIdentity<RazorPagesPizzaUser>(options => options.SignIn.RequireConfirmedAccount = true)
          .AddEntityFrameworkStores<RazorPagesPizzaAuth>();
    
    // Add services to the container.
    builder.Services.AddRazorPages();
    builder.Services.AddTransient<IEmailSender, EmailSender>();
    builder.Services.AddSingleton(new QRCodeService(new QRCodeGenerator()));
    
    var app = builder.Build();
    

    QRCodeService 在 Program.cs 内的 IoC 容器中注册为单一服务。

自定义多重身份验证

生成 QR 码后,可以将 QR 码嵌入“配置验证器应用”窗体中。

  1. 打开 Areas/Identity/Pages/Account/Manage/EnableAuthenticator.cshtml.cs 并进行下列更改:

    1. 将以下属性添加到 EnableAuthenticatorModel 类,以存储 QR 码的 base-64 字符串表示形式:

      public class EnableAuthenticatorModel : PageModel
      {
          private readonly UserManager<RazorPagesPizzaUser> _userManager;
          private readonly ILogger<EnableAuthenticatorModel> _logger;
          private readonly UrlEncoder _urlEncoder;
      
          public string QrCodeAsBase64 { get; set; }    
      
    2. 纳入 OnGetAsync 页处理程序中突出显示的更改:

      public async Task<IActionResult> OnGetAsync([FromServices] QRCodeService qrCodeService)
      {
          var user = await _userManager.GetUserAsync(User);
          if (user == null)
          {
              NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
          }
      
          await LoadSharedKeyAndQrCodeUriAsync(user);
          QrCodeAsBase64 = qrCodeService.GetQRCodeAsBase64(AuthenticatorUri);
      
          return Page();
      }
      

      在前面的页处理程序中,参数注入提供对 QRCodeService 单一服务的引用。

    3. 将以下 using 语句添加到文件顶部,以解析对 QRCodeService 的引用。 保存所做更改。

      using RazorPagesPizza.Services;
      
    4. 将突出显示的更改纳入到 GenerateQrCodeUri 方法。

      private string GenerateQrCodeUri(string email, string unformattedKey)
      {
          return string.Format(
              CultureInfo.InvariantCulture,
              AuthenticatorUriFormat,
              _urlEncoder.Encode("RazorPagesPizza"),
              _urlEncoder.Encode(email),
              unformattedKey);
      }
      

      这将设置 TOTP 应用中密钥的显示名称。

  2. Areas/Identity/Pages/Account/Manage/EnableAuthenticator.cshtml 中,进行以下突出显示的更改并保存:

    <li>
        <p>Scan the QR Code or enter this key <kbd>@Model.SharedKey</kbd> into your two factor authenticator app. Spaces and casing do not matter.</p>
        <div id="qrCode">
            <img alt="embedded QR code" src="data:image/png;base64,@Model.QrCodeAsBase64" />
        </div>
        <div id="qrCodeData" data-url="@Model.AuthenticatorUri"></div>
    </li>
            
    

    前面的标记将 base-64 编码图像嵌入页中。

测试多重身份验证

在“配置验证器应用”窗体上,你已对 QR 码做了所有需要的更改。 现在,你可以轻松测试 MFA 功能。

  1. 确保已保存所有更改。

  2. 使用 dotnet run 生成并运行应用。

  3. 导航到站点,并使用任一已注册用户登录(如果尚未登录)。 选择“Hello,[姓] [名]!”链接以导航到配置文件管理页面,然后选择“双因素身份验证”。

  4. 选择“添加验证器应用”按钮。

  5. 按照屏幕上的说明为此用户注册并验证身份验证器应用。

    以 Android 上的 Microsoft Authenticator 为例,请按照以下步骤将该帐户添加到应用:

    1. 打开 Microsoft Authenticator 应用。
    2. 选择右上角的 kebab 菜单(竖省略号)。
    3. 选择“添加帐户”。
    4. 选择“其他帐户(Google、Facebook 等)”。
    5. 按照指示扫描 QR 码。
  6. 在“验证码”文本框中输入 TOTP 应用提供的验证码。

  7. 选择“验证”。

    验证成功后,页面会显示“你的身份验证器应用已经过验证”横幅和一些恢复代码。

  8. 在 VS Code 中的“SQL Server”选项卡中,右键单击“RazorPagesPizza”数据库,然后选择“新建查询”。 输入以下查询,然后按 Ctrl+Shift+E 来运行它

    SELECT FirstName, LastName, Email, TwoFactorEnabled
    FROM dbo.AspNetUsers
    

    对于已登录的用户,输出显示 TwoFactorEnabled 列等于 1。 由于尚未为其他已注册的用户启用多重身份验证,因此记录的列值为 0

  9. 在 Web 应用中,选择“注销”,然后使用同一用户重新登录。

  10. 在“验证器代码”文本框中输入 TOTP 验证器应用提供的验证码。 选择“登录”按钮。

  11. 选择“Hello, [姓] [名]!”。 然后,选择“双因素身份验证”选项卡。

    由于已设置 Microsoft Authenticator,因此会显示以下按钮:

    • 禁用 2FA
    • 重置恢复代码
    • 设置验证器应用
    • 重置验证器应用
  12. 在 VS Code 的终端窗格中,按 Ctrl+C 来停止应用

摘要

在本单元中,你添加了向“配置验证器应用”窗格生成 QR 码的功能。 在下一单元中,你可以了解如何使用标识来存储声明并应用授权策略。