错误信息
NotAllowedError: The operation either timed out or was not allowed. See: https://www.w3.org/TR/webauthn-2/#sctn-privacy-considerations-client.
也可能输出为
- NotAllowedError: The operation either timed out or was not allowed.
- NotAllowedError: CredentialsContainer request is not allowed.
上面是 Chromium 的文本(旧版本没有“See: …”链接)。Firefox 显示的是“CredentialsContainer request is not allowed.”(已在没有认证器的无头 Firefox 157 中复现)。消息因浏览器而异;只有 `e.name` 是固定的。
WebAuthn navigator.credentials.get() / create() — DOMException NotAllowedError (Chromium; Firefox wording in aliases)
含义
这是浏览器对 WebAuthn 失败给出的兜底错误。规范有意让网页无法区分“用户取消了”“已超时”“没有认证器持有匹配的凭证”和“该请求在当前上下文中不被允许”,这样网站就无法探测设备上存在哪些凭证(链接中的隐私章节解释了原因)。因此,你的代码只能把它当作“没有产生凭证”,并提供其他途径;真正的原因要靠复现来查找,而不是靠阅读错误信息。
原因
这个认证器上没有 allowCredentials 中的任何凭证
常见该账号的通行密钥在另一台设备上、已被删除,或者是在另一个 RP ID 下注册的。浏览器会一直等待匹配的认证器,直到超时,然后报告 NotAllowedError。
用户关闭了对话框,或者已超时
常见关闭浏览器的通行密钥面板、生物识别验证失败次数过多,或者在耗时较长的安全密钥流程中把 `timeout` 设得太短,结果都一样。
未经用户操作或在隐藏页面中调用
偶见尤其是 Safari,要求 `create()`/`get()` 必须在响应点击时执行;如果调用之前有一个等待慢速网络请求的 `await`,就可能丢失用户激活状态。后台标签页,以及没有 `publickey-credentials-*` 权限的跨源 iframe,也会失败。
pubKeyCredParams 中没有受支持的算法
偶见如果认证器不支持你列出的任何一种 COSE 算法,注册会失败并报出 NotAllowedError,而不是更具体的错误。
修复方法
- 1.
按“没有凭证”处理,并提供替代方案
不要显示吓人的错误信息。提供其他登录方式、换用另一台设备(混合/QR 码流程),或者注册新的通行密钥。
js try { const credential = await navigator.credentials.get({ publicKey: options }); await finishLogin(credential); } catch (e) { if (e.name === "NotAllowedError") { // Cancelled, timed out, or no passkey for this account on this device: offer alternatives. showOtherSignInOptions(); } else { throw e; } } - 2.
注册时提供常用算法
列出 ES256、EdDSA 和 RS256 几乎就能覆盖所有认证器;相应地,你的服务器必须能验证这三种签名。
js // Registration: offer the algorithms authenticators actually support. pubKeyCredParams: [ { type: "public-key", alg: -7 }, // ES256 { type: "public-key", alg: -8 }, // EdDSA (Ed25519) { type: "public-key", alg: -257 }, // RS256 (Windows Hello and older security keys) ],
相关错误
SecurityError: The relying party ID is not a registrable domain suffix of, nor…WebAuthn navigator.credentials.create() / get()InvalidStateError: The user attempted to register an authenticator that contain…WebAuthn navigator.credentials.create() with excludeCredentialsUnexpected registration response origin "http://localhost:3000", expected "http…SimpleWebAuthn (@simplewebauthn/server)