Front-End-Checklist 实战指南:构建符合 WCAG 2.2 SC 3.3.8 的无障碍认证流程(autocomplete、OTP 自动填充与 Passkey 路径)
本篇指南基于 Front-End-Checklist 仓库中的无障碍认证规则(rule.md),系统讲解如何设计登录、MFA 与账户恢复流程,使其兼容密码管理器、粘贴、OTP 自动填充与 Passkey,而不依赖用户的记忆或誊写能力。读完后,你将掌握:autocomplete 令牌(username webauthn、current-password、one-time-code)的正确用法、可直接复制的 HTML 与 React 代码示例、自动化与手动验证清单,以及 WCAG 2.2 SC 3.3.8 对"非记忆依赖路径"的具体要求。
规则定位与元信息
在本仓库的规则体系中,"Provide accessible authentication methods" 是一条高优先级、进阶难度的认证可访问性规则,核心断言只有一句话:
认证流程应避免不必要的认知测试,并支持密码管理器、粘贴、OTP 自动填充和 Passkey 等辅助机制。
规则元数据(优先级 high / 难度 advanced / 预计耗时 25 分钟)在两个文件中保持一致:技能入口 SKILL.md 的 frontmatter,以及规则正文 rule.md 的头部声明。技能文件还声明了它的适用边界:用于审查登录、注册、MFA、CAPTCHA、恢复与重新认证(re-auth)流程,且要求评估完整的认证路径(含错误处理与备用方式),而不只是主登录表单。
仓库中对应的完整规则定义位于 accessible-authentication.mdx,其 frontmatter 标注了三个分类维度(accessibility / security / html)、表单子分类,以及三条权威资料来源:
| 资料来源 | 类型 | 角色 |
|---|---|---|
| WCAG 2.2 SC 3.3.8 Accessible Authentication (Minimum) | wcag | standard(标准依据) |
| W3C Understanding SC 3.3.8 | wcag | implementation(实现指导) |
| MDN HTML autocomplete attribute | mdn | reference(属性参考) |
从 frontmatter 的 relatedRules 结构看,这条规则与四条相邻规则显式关联,构成一个"认证可访问性"审查簇:
- paste-inputs.mdx:阻止粘贴是认证流程中最常见的直接违规点;
- password-field-security.mdx:密码字段语义、显示切换与密码管理器支持;
- form-captcha.mdx:反滥用控制往往是合规替代路径断裂之处;
- session-timeout-recovery.mdx:会话过期后的重新认证与恢复仍需可用。
核心原理:为什么"反认知测试"会同时提升安全
原文档给出的论点是:当存在可行的辅助路径时,认证不应依赖用户记忆、誊写或手工复现信息的能力。好的无障碍认证通常同时提升安全性——因为它与密码管理器、基于设备的验证和 Passkey 协作,而不是与它们对抗。
原文档列出了典型的"不必要的摩擦"模式:
- 阻止粘贴(blocked paste);
- 自研 OTP 输入组件,破坏了标准自动填充;
- 要求誊写的 CAPTCHA;
- 用"备份问题"式的记忆证明替代基于持有物(possession-based)的验证。
这些摩擦的实际代价包括:
- 认知障碍在用户做任何事情之前就先阻断了账户访问;
- 对密码管理器不友好会诱发更弱、被复用的密码;
- 语音输入、切换设备、纯键盘用户在被禁用复制/粘贴和自动填充时付出更多操作成本;
- 恢复流程和 MFA 步骤经常失败——哪怕主登录表单本身看起来没问题。
代码示例:密码管理器与 OTP 友好的字段
下面完整继承原文档的三段示例代码。第一段是登录 + OTP 场景的标准字段写法:
<!-- Better: password-manager and OTP-friendly fields -->
<label for="email">Email</label>
<input id="email" name="email" type="email" autocomplete="username webauthn">
<label for="password">Password</label>
<input
id="password"
name="password"
type="password"
autocomplete="current-password">
<label for="otp">Verification code</label>
<input
id="otp"
name="otp"
inputmode="numeric"
autocomplete="one-time-code">
三个字段各对应一个关键的 autocomplete 令牌:
autocomplete="username webauthn":用户名字段。webauthn令牌(多令牌空格分隔是合法写法)提示浏览器"此用户标识可用于 Passkey/WebAuthn 注册与登录",让支持 WebAuthn 的浏览器把该用户与 Passkey 凭据关联起来,这是"非记忆依赖路径"的前置语义;autocomplete="current-password":登录密码字段。密码管理器据此识别"这是要取回已存密码"的场景,与注册场景的new-password区分(后者在 password-field-security.mdx 中有进一步说明);autocomplete="one-time-code"配合inputmode="numeric":一次性验证码字段。one-time-code令牌是现代浏览器/OS 对 SMS 验证码与邮件代码自动填充的识别依据,inputmode="numeric"则让移动端直接弹出数字键盘,减少误输入。
第二段是 React 组件写法,注意 autoComplete、inputMode 是 React 的驼峰属性名,且保留了单输入框而非拆分为六个格子:
function VerifyCodeField({
onSubmit,
}: {
onSubmit: (code: string) => void
}) {
return (
<form
onSubmit={(event) => {
event.preventDefault()
const formData = new FormData(event.currentTarget)
onSubmit(String(formData.get('otp') ?? ''))
}}
>
<label htmlFor="otp">Enter the verification code</label>
<input
autoComplete="one-time-code"
id="otp"
inputMode="numeric"
name="otp"
type="text"
/>
<button type="submit">Continue</button>
</form>
)
}
从源码结构看,这个示例刻意用 FormData 从整个表单取值,意味着提交逻辑不依赖具体的输入控件结构——即使未来浏览器改变 OTP 自动填充的注入方式(例如写入隐藏字段或触发 input 事件),new FormData(event.currentTarget) 仍能以标准方式拿到值。type="text" 而非 type="tel" 也是有意为之:文本类型对自动填充兼容面更广,数字键盘由 inputMode 单独控制。
第三段是"非记忆依赖替代路径"的最小呈现——两个并列按钮:
<!-- Better: offer a non-memory-dependent alternative -->
<button type="button">Continue with a passkey</button>
<button type="button">Email me a sign-in link</button>
Passkey(基于 WebAuthn 的凭据)与 magic link(邮件签到链接)分别对应"基于设备的证明"与"发送到可信邮箱"两种路径,二者都不要求用户记忆或誊写任何信息。
最佳实践一:支持辅助输入(assisted entry)
原文档要求认证流程必须与以下机制协同工作:
- 密码管理器(password managers);
- 粘贴的凭据与验证码(pasted credentials and codes);
- 操作系统/浏览器 OTP 自动填充(OS/browser OTP autofill);
- 可用时的 Passkey 或设备审批(device approval)。
并给出一条硬约束:不要把一个一次性验证码拆进会破坏标准自动填充的自定义组件中,除非你已在真实浏览器中验证过行为。
这条约束在仓库的相邻规则中有直接佐证。paste-inputs.mdx 明确列出了三类"阻止粘贴"的反模式,并给出对应的正面写法:
<!-- Incorrect: Prevents pasting -->
<input type="password" onpaste="return false;" placeholder="Confirm Password">
<!-- Correct: Default behavior allows pasting -->
<label for="confirm-password">Confirm Password</label>
<input type="password" id="confirm-password" name="confirm-password">
<!-- Incorrect JavaScript -->
<script>
document.querySelector('#email').addEventListener('paste', (e) => {
e.preventDefault(); // Don't do this
});
</script>
该规则同样以 WCAG 2.2 SC 3.3.8 为第一来源,其给出的理由链与本篇一致:阻止粘贴会劝退使用长而唯一的密码管理器生成密码;精细运动控制受限的用户难以准确敲入长字符串;粘贴还降低了 IBAN、订单号等关键字段的键入错误率。因此"支持粘贴"与"支持自动填充"应视为同一项认证可访问性要求的两个侧面。
最佳实践二:至少一条不依赖记忆的路径
原文档要求:在登录、MFA、恢复三个环节中,至少有一条可行路径不依赖认知功能测试(cognitive function test)。被点名的合格路径有四类:
| 路径 | 机制 | 用户依赖 |
|---|---|---|
| Passkey | WebAuthn 凭据 + 设备生物识别/PIN | 持有可信设备 |
| 可信设备审批 | 推送审批(device approval) | 持有第二设备 |
| Magic link | 一次性链接发送到邮箱/手机 | 持有可信邮箱 |
| 密码管理器辅助 | 正确 autocomplete 语义下的自动填充 |
已配置的密码管理器 |
注意这条要求覆盖的是整条认证链路:即使主登录表单完全合规,如果 MFA 第二步只有一条"记住我 12 年前的安全答案"的路径,整条流程仍不满足规则。这也是技能文件中"评估完整认证路径,包括错误处理和备用方式"这一边界声明的落地含义。
最佳实践三:反滥用控制的相称性(proportionality)
原文档的表述是:如果在认证流程中使用 CAPTCHA 或其他滥用缓解手段,必须提供一条不强制记忆或誊写的替代路径。可访问性与防滥用不是相互竞争的目标,而是需要共同设计。
仓库将这一交叉点显式编码在规则关联关系中:form-captcha.mdx 被列为本规则的相关规则,关联理由(引自 accessible-authentication.mdx 的 frontmatter)是"反滥用控制往往正是合规替代认证路径断裂的地方"。实操含义是:审查 CAPTCHA 组件时,除检查组件本身的可达性外,还要回答"如果用户无法通过该 CAPTCHA,是否存在另一条完成认证的合规路径?"
标准映射:WCAG 2.2 SC 3.3.8 与例外
本规则映射到 WCAG 2.2 Success Criterion 3.3.8 Accessible Authentication (Minimum)。原文档特别澄清了一个常见误解:
实际目标不是"更少的安全",而是至少一条不依赖认知功能测试的可行路径。
原文档给出三条例外边界(Exceptions),审查时不应误报:
- 重复输入新密码:当系统不会把用户刚输入的密码回显给其本人时,"确认密码"式的重新输入是有效的安全例外(SC 3.3.8 的 c 条款精神即"不能简单重做/重输新输入的内容");
- MFA 与本规则兼容,但用户仍需至少一条不依赖记忆或誊写的实用路径;
- 无障碍不要求移除安全控制,而是要求选择用户实际能完成的安全控制。
验证清单:自动化检查 + 手动检查
自动化检查(Automated Checks)
原文档给出的两条静态/自动化检查方向:
- 在认证流程代码中搜索:阻止粘贴的事件处理器(
onpaste="return false"、paste事件的preventDefault())、自定义 OTP 拆分组件、缺失autocomplete属性的认证字段; - 校验
username、current-password、new-password、one-time-code四类字段是否使用了恰当的自动填充语义。
用 ripgrep 风格的模式表达,第一条检查可以落地为:
# 在认证相关目录中搜索阻止粘贴的处理器
rg -n "onpaste\s*=|'paste'|\\"paste\\"" auth/
# 搜索缺失 autocomplete 的认证输入
rg -n "type=\"(password|email|tel)\"" -g '!*.test.*' auth/
(以上为本仓库文档给出的检查思路的代码化表达,具体目录按项目结构调整。)
手动检查(Manual Checks)
原文档列出的四条人工验证步骤,构成一条完整的验收清单:
- 用密码管理器测试签到——自动填充应命中用户名和密码两个字段;
- 粘贴一个 OTP,或在浏览器支持时让它自动填充——单输入框 +
one-time-code语义下这一步应当"零成本"完成; - 演练恢复流程和 MFA 流程,而不只是主登录表单——这是最常被漏测的部分;
- 判定失败的判据:如果唯一可用路径要求用户记忆、誊写或解答认知测试,且不存在辅助替代路径,则检查不通过。
仓库中的配套工件与延伸阅读
围绕这条规则,仓库维护了三类配套工件,可用于持续工程化上述清单:
- 技能(Skill)工件:SKILL.md 定义了面向 Agent 的 Quick Reference / Check / Fix / Explain / Code Review 五段式工作流,把人工清单转化为可重复执行的审查提示;rule.md 则是其中"完整实现细节、代码示例与框架级指导"的引用文件,即本文的主体来源;
- 规则源文档(Source of Truth):accessible-authentication.mdx 包含规则的完整元数据、资料来源(sources)与相关规则图(relatedRules),是规则站点化与工具化消费的入口;
- 关联规则:paste-inputs.mdx、password-field-security.mdx、form-captcha.mdx、session-timeout-recovery.mdx 分别覆盖粘贴权限、密码字段安全、CAPTCHA 相称性与会话恢复,四者与本篇规则共同构成认证流程的完整可访问性审查面。
小结:无障碍认证的工程化落点可以压缩为四件事——为每个认证字段写对 autocomplete 语义、保持 OTP 单输入框可粘贴可自动填充、在登录/MFA/恢复链路上各保留一条 Passkey 或 magic link 式的非记忆路径、把 CAPTCHA 的替代路径纳入与主流程同等强度的验证。满足这四点后,流程在 WCAG 2.2 SC 3.3.8 意义上的合规性与在真实用户群体的完成率应当同步提升——这正是原文档"无障碍与防滥用共同设计"论断的实践含义。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00