You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS WebAuthn问题:关闭弹窗后无法重唤且提示用户取消请求错误

iOS WebAuthn弹窗取消后无法重新唤起的解决方案

在iOS的Safari或内嵌WKWebView中使用WebAuthn时,用户关闭弹窗后再次触发请求会抛出This request has been canceled by the user错误,这是iOS WebKit实现的特性——WebAuthn请求的上下文在用户取消后会被标记为失效,无法复用原有参数重新唤起。以下是具体的解决方法:

1. 每次唤起都获取全新的WebAuthn请求参数

iOS WebAuthn会绑定请求的唯一挑战(challenge)和上下文状态,用户取消后,原请求的参数(尤其是publicKey对象)会被视为无效。必须每次触发WebAuthn流程时,都从后端重新获取最新的注册/登录选项,不能缓存或复用之前的参数。

示例代码:

async function triggerWebAuthnLogin() {
  try {
    // 每次都从后端请求新鲜的options,而不是复用缓存值
    const freshOptions = await fetch('/api/webauthn/get-login-options')
      .then(res => res.json());
    
    const credential = await navigator.credentials.get({
      publicKey: freshOptions
    });
    
    // 将凭证提交给后端完成验证
    await fetch('/api/webauthn/verify-login', {
      method: 'POST',
      body: JSON.stringify(credential)
    });
  } catch (err) {
    if (err.name === 'NotAllowedError' && err.message.includes('canceled by the user')) {
      // 用户主动取消,无需额外处理,下次点击会重新发起请求
      console.log('用户取消了WebAuthn验证');
    } else {
      // 处理其他错误
      console.error('WebAuthn请求失败:', err);
    }
  }
}

2. 防止重复触发请求

如果用户快速多次点击触发按钮,可能导致多个WebAuthn请求叠加,iOS会直接拒绝后续请求。需要添加状态锁,在请求进行中禁用触发按钮,避免重复调用。

示例代码:

let isWebAuthnInProgress = false;

async function triggerWebAuthnLogin() {
  if (isWebAuthnInProgress) return;
  isWebAuthnInProgress = true;
  
  try {
    const freshOptions = await fetch('/api/webauthn/get-login-options')
      .then(res => res.json());
    const credential = await navigator.credentials.get({ publicKey: freshOptions });
    await fetch('/api/webauthn/verify-login', {
      method: 'POST',
      body: JSON.stringify(credential)
    });
  } catch (err) {
    // 错误处理逻辑
  } finally {
    isWebAuthnInProgress = false;
  }
}

3. 内嵌WKWebView场景的额外配置

如果是在iOS App的WKWebView中使用WebAuthn,还需要确保以下配置正确:

  • 确保App运行在iOS 13.0及以上版本(WebAuthn从iOS 13开始支持)
  • WKWebConfiguration需开启JavaScript支持(默认开启,但需确认未禁用)
  • 如果使用生物识别(FaceID/TouchID),需在Info.plist中添加对应的权限描述(如NSFaceIDUsageDescription)
  • 同样遵循“每次请求获取新参数”的规则,不能复用WebView中的旧请求上下文

为什么会出现这个问题?

iOS WebKit为了安全和请求生命周期管理,会在用户取消WebAuthn弹窗后销毁当前请求的上下文。后端生成的WebAuthn选项包含一次性的挑战值,这也是安全设计的一部分——每个请求的挑战都是唯一的,无法重复使用,因此必须重新获取新的选项才能发起有效的WebAuthn请求。

内容的提问来源于stack exchange,提问作者Xaber

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 09:02:31