为 ASP.NET Core 中的 TOTP 验证器应用启用 QR 码生成

ASP.NET Core 支持将验证器应用程序用于进行个人身份验证。 双因素身份验证 (2FA) 验证器应用使用基于时间的一次性密码算法 (TOTP),是行业推荐用于 2FA 的方法。 使用 TOTP 的 2FA 方法首选短信 2FA。 验证器应用提供 6-8 位代码,用户在确认他们的用户名和密码后必须输入该代码。 通常,验证器应用安装在智能手机上。

ASP.NET Core Web 应用模板支持验证器,但不提供对 QR 码生成的支持。 QR 码生成器可简化 2FA 的设置。 本文档提供了有关 Razor 页面和 MVC 应用如何将 QR 码生成添加到 2FA 配置页的指南。 有关适用于 Blazor Web 应用的指南,请参阅在 ASP.NET Core Blazor Web 应用中为 TOTP 验证器应用启用 QR 码生成

ASP.NET Core Web 应用模板支持验证器,但不提供对 QR 码生成的支持。 QR 码生成器可简化 2FA 的设置。 本文档会指导你将 QR 码生成添加到 2FA 配置页面。

使用 GoogleFacebook 等外部身份验证提供程序时不会进行双因素身份验证。 外部登录受外部登录提供程序提供的机制的保护。 例如,假设 Microsoft 身份验证提供程序需要硬件密钥或其他 2FA 方法。 如果默认模板强制执行“本地”2FA,那么用户需要满足两个 2FA 方法,这不是常用的方案。

将 QR 码添加到 2FA 配置页面

这些说明使用来自 https://davidshimjs.github.io/qrcodejs/ 存储库的 qrcode.js

  • qrcode.js JavaScript 库下载到项目中的 wwwroot\lib 文件夹。
  • 按照搭建 Identity 的基架中的说明生成 /Areas/Identity/Pages/Account/Manage/EnableAuthenticator.cshtml
  • /Areas/Identity/Pages/Account/Manage/EnableAuthenticator.cshtml 中,找到文件末尾的 Scripts 节:
@section Scripts {
    @await Html.PartialAsync("_ValidationScriptsPartial")
}
  • wwwroot/js 中新建名为 qr.js 的一个 JavaScript 文件,并添加以下代码以生成 QR 码:
window.addEventListener("load", () => {
  const uri = document.getElementById("qrCodeData").getAttribute('data-url');
  new QRCode(document.getElementById("qrCode"),
    {
      text: uri,
      width: 150,
      height: 150
    });
});
  • 更新 Scripts 部分以添加对之前下载的 qrcode.js 库的引用。
  • 通过调用添加 qr.js 文件以生成 QR 码:
@section Scripts {
    @await Html.PartialAsync("_ValidationScriptsPartial")

    <script type="text/javascript" src="~/lib/qrcode.js"></script>
    <script type="text/javascript" src="~/js/qr.js"></script>
}
  • 删除链接到这些说明的段落。

运行应用,并确保可以扫描 QR 码并验证验证器证明的代码。

更改 QR 码中的站点名称

QR 码中的站点名称取自你在最初创建项目时选择的项目名称。 可以通过在 /Areas/Identity/Pages/Account/Manage/EnableAuthenticator.cshtml.cs 中查找 GenerateQrCodeUri(string email, string unformattedKey) 方法来更改站点名称。

模板中的默认代码如下所示:

private string GenerateQrCodeUri(string email, string unformattedKey)
{
    return string.Format(
        AuthenticatorUriFormat,
        _urlEncoder.Encode("Razor Pages"),
        _urlEncoder.Encode(email),
        unformattedKey);
}

string.Format 的调用中的第二个参数是你的站点名称,取自你的解决方案名称。 它可以更改为任何值,但必须始终是 URL 编码的。

使用不同的 QR 码库

可以使用你的首选库来取代 QR 码库。 HTML 包含一个 qrCode 元素,可以通过你的库所提供的任何机制将 QR 码放在该元素中。

QR 码的格式正确的 URL 位于:

  • 模型的 AuthenticatorUri 属性中。
  • qrCodeData 元素中的 data-url 属性中。

TOTP 客户端和服务器时间倾斜

TOTP(基于时间的一次性密码)身份验证依赖于具有准确时间的服务器和验证器设备。 令牌仅持续 30 秒。 如果 TOTP 2FA 登录失败,请检查服务器时间是否准确,最好同步到准确的 NTP 服务。