SMS OTP 表单最佳实践
了解如何优化 SMS OTP 表单并改善用户体验。
要求用户提供通过 SMS 发送的 OTP(一次性密码)是确认用户电话号码的常用方法。以下列出了几个 SMS OTP 用例:
- **双重身份验证。**除了用户名和密码之外,SMS OTP 还可以用作强烈信号,表明该帐户归属于收到 SMS OTP 的人所有。
- **电话号码验证。**某些服务使用电话号码作为用户的主要标识符。在此类服务中,用户可以输入他们的电话号码和通过短信收到的 OTP 来证明他们的身份。有时它与 PIN 结合构成双重身份验证。
- **帐户恢复。**当用户无法访问其帐户时,需要有一种方法来恢复。向他们注册的电子邮件地址发送电子邮件或向他们的电话号码发送 SMS OTP 是常见的帐户恢复方法。
- **支付确认。**在支付系统中,一些银行或信用卡发卡机构出于安全原因要求付款人进行额外的验证。SMS OTP 通常用于此目的。
本文阐述了为上述用例构建 SMS OTP 表单的最佳实践。
清单 #
要通过 SMS OTP 提供最佳用户体验,请执行以下步骤:
- 将
<input>元素用于:type="text"inputmode="numeric"autocomplete="one-time-code"
- 将
@BOUND_DOMAIN #OTP_CODE用作 OTP SMS 消息的最后一行。 - 使用 WebOTP API。
使用 <input> 元素 #
使用含 <input> 元素的表单是您可以遵循的最重要的最佳实践,因为它适用于所有的浏览器。即使本文中的其他建议在某些浏览器中不起作用,用户仍然可以手动输入并提交 OTP。
<form action="/verify-otp" method="POST">
<input type="text"
inputmode="numeric"
autocomplete="one-time-code"
pattern="\d{6}"
required>
</form>
以下是确保输入字段充分利用浏览器功能的一些想法。
type="text" #
由于 OTP 通常是五位或六位数字,因此对输入字段使用 type="number" 可能看起来很直观,因为它会将移动键盘更改为全数字。不推荐这样做,因为浏览器希望输入字段是可数的而不是多个数字的序列,这可能会导致意外行为。使用 type="number" 会导致在输入字段旁边显示向上和向下按钮;按这些按钮会增加或减少数字,并可能删除前面的零。
请改用 type="text"。这不会将移动键盘转换为全数字,这样较好,因为使用 inputmode="numeric" 的下一个技巧可以完成这项工作。
inputmode="numeric" #
使用 inputmode="numeric" 将移动键盘更改为全数字。
一些网站将 type="tel" 用于 OTP 输入字段,因为它也会在聚焦时将移动键盘转换为全数字(包括 * 和 #)。这早在 inputmode="numeric" 还没有得到广泛支持时就得到了应用。由于 Firefox 开始支持 inputmode="numeric" ,因此无需使用语义不正确的 type="tel"。
autocomplete="one-time-code" #
autocomplete 属性允许开发人员指定浏览器提供自动填充协助的权限,并通知浏览器该字段中预期的信息类型。
借助 autocomplete="one-time-code",当用户在表单打开期间收到 SMS 消息时,操作系统将试探性地解析 SMS 中的 OTP,并且键盘会建议用户输入的 OTP。它仅适用于 iOS、iPadOS 和 macOS 上的 Safari 12 及更高版本,但我们强烈建议使用它,因为它是改善这些平台上 SMS OTP 体验的简单方法。
autocomplete="one-time-code" 改善了用户体验,但通过确保 SMS 消息符合源绑定消息格式,您还可以做更多的事情。
格式化 SMS 文本 #
遵循通过 SMS 发送的源绑定的一次性代码规范,可以增强用户输入 OTP 的体验。
格式规则很简单:接收域以 @ 开头,OTP 以 # 开头,以此完成 SMS 消息。
例如:
Your OTP is 123456
@web-otp.glitch.me #123456
使用 OTP 消息的标准格式可以更轻松、更可靠地从中提取代码。将 OTP 代码与网站相关联使诱骗用户向恶意网站提供代码变得更加困难。
使用这种格式有几个好处:
- OTP 将绑定到域。如果用户所在的域不是 SMS 消息中指定的域,则不会出现 OTP 建议。这也降低了网络钓鱼攻击和潜在帐户劫持的风险。
- 浏览器现在将能够可靠地提取 OTP,而无需依赖神秘和不稳定的启发式方法。
当网站使用 autocomplete="one-time-code" ,iOS 14 或更高版本的 Safari 将按照上述规则建议 OTP。
这种 SMS 消息格式也有利于 Safari 以外的浏览器。Chrome、Opera 和 Android 上的 Vivaldi 也支持使用 WebOTP API 的源绑定一次性代码规则,但不是通过 autocomplete="one-time-code" 。
使用 WebOTP API #
WebOTP API 提供对在 SMS 消息中收到的 OTP 的访问。通过调用 otp 类型 (OTPCredential) 的 navigator.credentials.get() ( 其中 transport 包含 sms),网站将等待符合源绑定一次性代码的 SMS 发送以及用户授予的访问权限。将 OTP 发送给 JavaScript 后,网站可以在表单中使用它或将其直接发布到服务器。
navigator.credentials.get({
otp: {transport:['sms']}
})
.then(otp => input.value = otp.code);
请参阅使用 WebOTP API 验证 Web 上的电话号码以详细了解如何使用 WebOTP API,或复制并粘贴以下代码段。(确保 <form> 元素正确设置了 action 和 method 属性。)
// Feature detection
if ('OTPCredential' in window) {
window.addEventListener('DOMContentLoaded', e => {
const input = document.querySelector('input[autocomplete="one-time-code"]');
if (!input) return;
// Cancel the WebOTP API if the form is submitted manually.
const ac = new AbortController();
const form = input.closest('form');
if (form) {
form.addEventListener('submit', e => {
// Cancel the WebOTP API.
ac.abort();
});
}
// Invoke the WebOTP API
navigator.credentials.get({
otp: { transport:['sms'] },
signal: ac.signal
}).then(otp => {
input.value = otp.code;
// Automatically submit the form when an OTP is obtained.
if (form) form.submit();
}).catch(err => {
console.log(err);
});
});
}
照片作者:Jason Leung,来源:Unsplash。