使用 WebOTP API 在网页上验证电话号码

帮助用户处理通过短信接收的动态密码

什么是 WebOTP API?

如今,世界上大多数人都拥有移动设备,开发者通常会使用电话号码作为其服务用户的标识符。

验证电话号码的方法有很多种,但通过短信发送随机生成的动态密码 (OTP) 是最常见的方法之一。将此代码发送回开发者的服务器,即可证明您对相应电话号码的控制权。

此理念已在许多场景中部署,以实现以下目标:

  • 作为用户标识符的电话号码。注册新服务时,某些网站会要求您提供电话号码(而不是电子邮件地址),并将其用作账号标识符。
  • 两步验证。登录时,网站除了要求提供密码或其他知识因素外,还会要求提供通过短信发送的一次性验证码,以提高安全性。
  • 付款确认。当用户付款时,要求用户提供通过短信发送的一次性验证码有助于验证用户的意图。

当前流程会给用户带来不便。在短信中查找一次性密码,然后将其复制并粘贴到表单中,这种做法非常麻烦,会降低关键用户体验历程中的转化率。许多全球最大的开发者一直以来都希望能够简化此流程。Android 有一个专门用于执行此操作的 APIiOSSafari 也是如此。

借助 WebOTP API,您的应用可以接收与应用网域绑定的特殊格式的消息。这样一来,您就可以通过编程方式从短信消息中获取 OTP,并更轻松地验证用户的电话号码。

实例展示

假设某用户想通过某个网站验证自己的电话号码。网站通过短信向用户发送一条短信,用户输入该短信中的动态密码,以验证电话号码的所有权。

借助 WebOTP API,用户只需点按一下即可完成这些步骤,如视频所示。收到短信后,系统会弹出底部工作表,提示用户验证其电话号码。在底部工作表中点击验证按钮后,浏览器会将 OTP 粘贴到表单中,然后提交表单,而无需用户按继续

下图展示了整个流程。

WebOTP API 图

亲自试用演示版。它不会要求您提供电话号码,也不会向您的设备发送短信,但您可以从其他设备发送短信,只需复制演示中显示的文字即可。之所以可行,是因为在使用 WebOTP API 时,发件人是谁并不重要。

  1. 在 Android 设备上,使用 Chrome 84 或更高版本前往 https://chrome.dev/web-otp-demo
  2. 通过另一部手机向您的手机发送以下短信。
Your OTP is: 123456.

@chrome.dev #123456

您是否收到了短信,并看到提示您在输入区域中输入验证码? 这就是 WebOTP API 的用户体验。

使用 WebOTP API 包含三个部分:

  • 正确添加了注释的 <input> 标记
  • Web 应用中的 JavaScript
  • 通过短信发送的格式化消息文本。

我将先介绍 <input> 标记。

<input> 标记添加注释

WebOTP 本身无需任何 HTML 注释即可正常运行,但为了实现跨浏览器兼容性,我强烈建议您向用户输入 OTP 的 <input> 标记添加 autocomplete="one-time-code"

这样一来,即使 Safari 14 或更高版本不支持 WebOTP,当用户收到格式如设置短信格式中所述的短信时,Safari 14 或更高版本也会建议用户使用 OTP 自动填充 <input> 字段。

HTML

<form>
  <input autocomplete="one-time-code" required/>
  <input type="submit">
</form>

使用 WebOTP API

由于 WebOTP 非常简单,只需复制并粘贴以下代码即可。无论如何,我都会向您介绍正在发生的情况。

JavaScript

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.log(err);
    });
  });
}

功能检测

功能检测与其他许多 API 相同。监听 DOMContentLoaded 事件将等待 DOM 树准备好进行查询。

JavaScript

if ('OTPCredential' in window) {
  window.addEventListener('DOMContentLoaded', e => {
    const input = document