发布于 2026-01-06 0 阅读
0

使用 WebOTP 获得更佳的双因素身份验证体验

使用 WebOTP 获得更佳的双因素身份验证体验

双因素身份验证 (2FA) 是提升应用程序用户帐户安全性的有效方法。它有助于防止常见的密码安全问题,例如用户选择容易被猜到的密码或在多个网站上重复使用同一密码。实现双因素身份验证的方法有很多种,包括短信验证、使用身份验证器应用程序和 WebAuthn。

短信验证是目前应用最广泛的验证方式,而且不会过时,因此作为开发者,我们有责任尽最大努力为用户打造最佳的短信双因素认证体验。WebOTP API 是我们可以帮助用户减少登录过程中的摩擦,甚至提供一定程度的防钓鱼保护的一种途径。

什么是 WebOTP API?

WebOTP API是凭证管理 API的扩展。凭证管理 API 最初允许我们在浏览器的密码管理器中存储和访问凭证,但现在已涵盖WebAuthn和双因素身份验证。WebOTP API 允许我们请求用户授权,从收到的短信中读取双因素身份验证代码。

当您集成 WebOTP API 后,登录流程的第二步就可以从繁琐的从短信中读取并复制数字,简化为只需按一下按钮即可。相信您也会认同,这是一项巨大的改进。

一段动画展示了登录过程:输入用户名和密码后,会弹出一个权限对话框,请求读取短信中的双因素身份验证 (2FA) 验证码。获得批准后,验证码会被输入到输入框中,然后表单会被提交。

它是如何运作的?

要实现 WebOTP,您需要做两件事:

  1. 更新您发送的 WebOTP 格式消息
  2. 在登录页面添加一些 JavaScript 代码,以请求读取消息的权限。

短信

为了让 WebOTP API 将消息识别为传入的双因素身份验证 (2FA) 代码,您需要在发送的消息末尾添加一行。该行必须包含一个@符号,后跟用户将要登录的网站域名,然后是一个空格,再是一个#符号,最后是验证码本身。如果您的用户正在登录某个网站example.com,并且您发送给他们的验证码是某个特定网站123456,则消息应如下所示:

您登录应用程序的代码是 123456

@example.com #123456

域名将消息与用户应该登录的网站关联起来。这有助于防范网络钓鱼。如果用户登录的网站域名与消息中的域名不匹配,WebOTP 就无法通过短信请求验证码。当然,这无法阻止用户复制短信中的验证码,但如果用户习惯了这种行为,可能会让他们有所顾虑。

JavaScript

一旦你的消息格式设置正确,你需要第二因素页面上的一些 JavaScript 代码来触发 WebOTP API,请求用户访问消息的权限并收集代码。

这段代码的最简版本如下所示:

if ('OTPCredential' in window) {
  navigator.credentials.get({
    otp: {
      transport: ['sms']
    }
  }).then((otp) => {
    submitOTP(otp.code);
  });
}

Enter fullscreen mode Exit fullscreen mode

我们要求navigator.credentials对象从短信传输中获取一次性密码 (OTP)。如果浏览器检测到包含正确域名和验证码的短信,则会提示用户授予访问权限。如果用户批准,则 Promise 会解析为一个otp包含特定code属性的对象。然后,您可以将该验证码提交到表单,完成用户的登录过程。

更完整的代码版本(可以处理诸如查找输入框和表单、表单提交后取消请求以及请求成功后提交表单等操作)如下所示:

if ('OTPCredential' in window) {
  window.addEventListener('DOMContentLoaded', e => {
    const input = document.querySelector('input[autocomplete="one-time-code"]');
    if (!input) return;
    const ac = new AbortController();
    const form = input.closest('form');
    if (form) {
      form.addEventListener('submit', e => ac.abort());
    }
    navigator.credentials.get({
      otp: { transport:['sms'] },
      signal: ac.signal
    }).then(otp => {
      input.value = otp.code;
      if (form) {
        form.submit();
      }
    }).catch(err => {
      console.error(err);
    });
  });
}

Enter fullscreen mode Exit fullscreen mode

这种方法适用于很多网站,但是复制粘贴代码并不是分享代码的最佳方式,所以我想到了一种更简单的方法。

使用 Web 组件的声明式 WebOTP

在 Safari 浏览器中,您可以通过<input>向 OTP 代码元素添加一个属性来实现与 WebOTP API 类似的功能。设置此属性后,autocomplete="one-time-code"Safari 会通过自动完成功能提供短信中的验证码。

受此启发,我希望 WebOTP 的使用也能同样简单。因此,我发布了一个 Web 组件,即 ` <component>`<web-otp-input>组件,它负责处理整个流程。您可以在 GitHub 上查看所有代码及其使用方法。例如,您可以将该组件作为 ES 模块添加到您的页面中:

<script type="module" src="https://unpkg.com/@philnash/web-otp-input"></script>

Enter fullscreen mode Exit fullscreen mode

或者通过 npm 将其安装到您的项目中:

npm install @philnash/web-otp-input

Enter fullscreen mode Exit fullscreen mode

并将其导入到您的应用程序中:

import { WebOTPInput } from "@philnash/web-otp-input";

Enter fullscreen mode Exit fullscreen mode

然后,你可以像这样将它包裹<web-otp-input>在现有的<input>元素周围:<form>

<form action="/verification" method="POST">
  <div>
    <label for="otp">Enter your code:</label>
    <web-otp-input>
      <input type="text" autocomplete="one-time-code" inputmode="numeric" id="otp" name="otp" />
    </web-otp-input>
  </div>
  <button type="submit">Submit</button>
</form>

Enter fullscreen mode Exit fullscreen mode

这样,任何使用支持 WebOTP 的浏览器的用户都会自动体验 WebOTP,而无需编写任何额外的 JavaScript 代码。

WebOTP:更佳体验

WebOTP API 让短信双因素认证体验更佳。对于支持该 API 的浏览器,用户可以轻松输入作为第二因素发送的验证码。

甚至在某些情况下,它也能用于桌面浏览器。例如,如果用户在桌面和安卓设备上都安装了 Chrome 浏览器,并且都登录了 Google 帐户,那么在桌面设备上登录后,移动设备上会收到一条通知,询问是否允许将验证码发送到桌面。在移动设备上批准该通知后,验证码就会传输到桌面浏览器。您甚至无需编写额外的代码来处理这种情况,只需要本文中提供的 JavaScript 代码即可。

有关 WebOTP 的更多信息,请查看以下文章:

如果您正在构建双因素身份验证或手机验证,请考虑同时实现 WebOTP API,以简化用户的操作流程。

文章来源:https://dev.to/philnash/better-two-factor-authentication-experiences-with-webotp-1ncm