WWDC Quick Look 💓 By SwiftGGTeam
What’s new in passkeys

What’s new in passkeys

观看原视频

Highlight

iOS、iPadOS、macOS、visionOS 26 在 passkey 生命周期的注册、维护、升级、发现、迁移五个阶段各推出一组 API。


核心内容

旧的注册流程让人难受。用户点”用邮箱注册”,要先填邮箱,再填名字、姓氏,再生成强密码,再点继续,至少四步。FIDO 联盟 2025 年的调研里,69% 的人已经至少有一个 passkey;Google 公布密码用户的登录成功率只有 passkey 用户的四分之一;TikTok 的 passkey 登录成功率到了 97%。可即便如此,注册仍然要走一遍密码表单——passkey 是后补的,不是起点。

Account Creation API 把注册环节重做。用户点注册之后,系统直接弹一个 Sheet,姓名、邮箱、即将创建的 passkey 全部预填好,Face ID 一扫就完成(03:43)。预填字段可改,点字段会出 picker,里面是系统建议的几个值,也能手动输入。整个交互对接的是系统密码 App 或第三方凭证管理器,账户从第一秒就有 passkey,不需要先建一个密码账户再”升级”。

剩下四个更新围绕 passkey 的后续阶段。Signal API 让 App 在改用户名、吊销 passkey、删除密码后通知凭证管理器,避免凭证管理器显示过期信息。Automatic Passkey Upgrade 让已有密码账户在密码登录后静默生成 passkey,没有弹窗。Passkey Management Endpoints 是 well-known URL 标准,凭证管理器可以读取 enroll/manage URL,主动提示用户升级。Import/Export 让凭证在不同凭证管理器间直传,不落地中间文件。

详细内容

注册的核心代码只有一段(06:33)。新建一个 ASAuthorizationAccountCreationProvider,调用 createPlatformPublicKeyCredentialRegistrationRequest 生成 request,再交给 ASAuthorizationController 执行。

@Environment(\.authorizationController) var authorizationController

func performPasskeySignUp() async throws {
    let provider = ASAuthorizationAccountCreationProvider()
    let request = provider.createPlatformPublicKeyCredentialRegistrationRequest(
        acceptedContactIdentifiers: [.email, .phoneNumber],
        shouldRequestName: true,
        relyingPartyIdentifier: "example.com",
        challenge: try await fetchChallenge(),
        userID: try await fetchUserID()
    )

    do {
        let result = try await authorizationController.performRequest(request)
        if case .passkeyAccountCreation(let account) = result {
            // Register new account on backend
        }
    } catch ASAuthorizationError.deviceNotConfiguredForPasskeyCreation {
        showPasswordSignUpForm = true
    } catch ASAuthorizationError.canceled {
        showPasswordSignUpForm = true
    } catch ASAuthorizationError.preferSignInWithApple {
        await performSignInWithApple()
    } catch { ... }
}

关键点:

  • acceptedContactIdentifiers 声明 App 接受哪些联系人标识符,传 .email.phoneNumber 两个;用户最后只会回传一个,那个值同时充当 passkey 的 user name 标签。
  • shouldRequestName 控制是否要姓名;非必要别开,能少一个字段就少一个字段。
  • relyingPartyIdentifierchallengeuserID 与标准 passkey 注册一致:域名、服务端一次性 challenge、稳定唯一的账户 ID。
  • 三个特定错误必须各自处理:deviceNotConfiguredForPasskeyCreation 表示设备没设密码、不能建 passkey,降级到传统表单;canceled 表示用户关掉了系统 Sheet,同样降级;preferSignInWithApple 仅在 App 支持 Sign in with Apple 时才会抛出,意味着用户已有 Sign in with Apple 账户,这时应直接发起 Sign in with Apple 请求,让用户落到已有账户。
  • performRequest 返回的 ASAuthorizationResult 里 unwrap 出 .passkeyAccountCreation(let account),拿到 contact identifier、姓名(若请求过)和 passkey 对象。

第二段是 Signal API(12:3013:07)。用户在 App 改了邮箱后,调用 ASCredentialUpdater().reportPublicKeyCredentialUpdate 把新名字推给凭证管理器;吊销 passkey 时调用 reportAllAcceptedPublicKeyCredentials 传入仍然有效的 credential ID 集合,凭证管理器会删除不在集合里的 passkey。Web 端有对应的 PublicKeyCredential.signalCurrentUserDetailssignalAllAcceptedCredentials

第三段是 Automatic Passkey Upgrade(15:36)。

func signIn() async throws {
    let accountDetails = try await signInWithPassword()
    guard !accountDetails.hasPasskey else { return }

    let provider = ASAuthorizationPlatformPublicKeyCredentialProvider(
        relyingPartyIdentifier: "example.com")

    let request = provider.createCredentialRegistrationRequest(
        challenge: try await fetchChallenge(),
        name: accountDetails.userName,
        userID: accountDetails.userID,
        requestStyle: .conditional
    )

    do {
        let passkey = try await authorizationController.performRequest(request)
        // Save new passkey to the backend
    } catch { ... }
}

关键点:

  • 入口在密码登录成功之后;先确认账户没有 passkey,再发起注册请求,避免重复创建。
  • requestStyle: .conditional 是开关——加了它系统才会走静默路径;条件不满足(比如设备不支持 passkey)会静默失败,没有 UI、没有干扰。
  • 成功后系统会推送通知告知用户已添加 passkey;失败什么也不显示,下次登录可以再尝试,没有任何成本。

核心启发

  • 做什么:把所有新注册路径切到 Account Creation API,把传统表单作为 fallback。

    • 为什么值得做:注册步骤从四步压缩到一步 Face ID,用户拿到的是带 passkey 的账户而非密码账户,登录成功率会显著提升。
    • 怎么开始:实现 ASAuthorizationAccountCreationProvider 流程,处理 deviceNotConfiguredForPasskeyCreationcanceled 时回落到表单;若 App 支持 Sign in with Apple,再处理 preferSignInWithApple 走原账户。
  • 做什么:在所有改用户名、删账户、吊销 passkey 的入口接 Signal API,让凭证管理器始终显示最新状态。

    • 为什么值得做:凭证管理器显示旧用户名或已吊销的 passkey 会让用户登录卡住,是 passkey 体验里最常见的隐性失败点。
    • 怎么开始:账户设置里改邮箱后调用 reportPublicKeyCredentialUpdate;吊销列表更新后调用 reportAllAcceptedPublicKeyCredentials 传当前合法 ID 集合;用户改用全 passkey 后调用 reportUnusedPasswordCredential 让旧密码从凭证管理器消失。
  • 做什么:给现有密码用户加 Automatic Passkey Upgrade,每次密码登录都试一次。

    • 为什么值得做:存量密码账户是 passkey 推广最大的阻力,静默升级让用户在毫无感知的情况下迁移到 passkey,下一次登录就能享受 Face ID。
    • 怎么开始:在密码登录成功的回调里检查 hasPasskey,没有就发起 requestStyle: .conditional 的 registration 请求,失败什么也不做。
  • 做什么:服务端实现 /.well-known/passkey-endpoints,公开 enroll 与 manage 的 URL。

    • 为什么值得做:凭证管理器可以读取这个端点,在用户还在用密码时主动引导升级 passkey,等于服务方多了一个免费的获客入口。
    • 怎么开始:在 well-known 路径下返回 JSON,列出 enroll 和 manage 两个 URL;登录页接受这些深链接,落到对应的注册或管理流程。

关联 Session

评论

GitHub Issues · utterances