练习 - 配置多重身份验证

已完成

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

生成 QR 码

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

添加 QR 码服务

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

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

    dotnet add package QRCoder --version 1.6.0
    
  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 编码字符串。 传递给 GetGraphic 的整数值决定了 QR 码的尺寸。 在这种情况下,生成的 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();
    

    QRCodeServiceProgram.cs 的 IoC 容器中注册为单例服务。

自定义多重身份验证

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

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

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

      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)
          {
              return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
          }
      
          await LoadSharedKeyAndQrCodeUriAsync(user);
          QrCodeAsBase64 = qrCodeService.GetQRCodeAsBase64(AuthenticatorUri);
      
          return Page();
      }
      

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

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

      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 class="alert alert-info">Learn how to <a href="https://go.microsoft.com/fwlink/?Linkid=852423">enable QR code generation</a>.</div>
        <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. 选择右上角的烤肉串菜单(垂直省略号)。
    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. Authenticator 代码 文本框中,输入 TOTP 验证器应用中的验证码。 选择“ 登录 ”按钮。

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

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

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

概要

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