Passkeys 新特性
What's new in passkeys
2025年6月9日
一句话判断
Passkeys 的拼图终于补完了——从注册(Account Creation API)到维护(Signal API 同步凭证变更)到升级(零摩擦自动创建 passkey)到发现(well-known 端点)再到迁移(凭证导入导出),全链路打通。这是对”密码该怎么死”这个问题最完整的回答。
这场 Session 讲了什么
五个独立但互补的更新,覆盖了 passkey 生命周期的每个阶段。
Account Creation API 是注册环节的重做。用户点”用邮箱注册”后,系统弹出一个 Sheet,预填了姓名、邮箱和 passkey 信息,Face ID 一扫就完成注册——不需要填表单、不需要设密码。实现上只需要初始化 ASCredentialProvider、创建 passkey registration request、通过 ASAuthorizationController 执行。三个特有错误需要处理:deviceNotConfiguredForPasskeyCreation(设备未配置 passkey)、canceled(用户关闭 Sheet)、preferSignInWithApple(已有 Apple 登录账户,防止重复注册)。
Signal API 解决的是凭证维护问题。当用户在 App 里改了用户名、吊销了 passkey 或彻底移除了密码,用 ASCredentialUpdater 的 report 方法通知凭证管理器。凭证管理器(比如系统密码 App)会立即更新显示信息。Web 端有对应的 WebAuthn 标准方法。
Automatic Passkey Upgrades 是零摩擦的密码到 passkey 迁移。用户用密码登录后,App 把 registration request 的 style 设成 conditional,系统会在后台静默创建 passkey 并推送通知。没有弹窗、没有中断。如果条件不满足(比如设备不支持),静默失败。
Passkey Management Endpoints 是一个 well-known URL 标准。服务端在 /.well-known/passkey-endpoints 返回 JSON,指定 enroll 和 manage 的 URL。凭证管理器可以读取这个端点,在 App 还用密码登录时就提示”可以升级 passkey”。
Import/Export 是凭证在不同凭证管理器之间迁移的能力。整个过程在 App 之间直传,Face ID 保护,不生成中间文件——比传统的 CSV 导出安全得多。
值得深挖的点
Account Creation API 的 UX 设计值得所有注册流程参考
传统的注册流程是”填表单 -> 验证邮箱 -> 设密码 -> 可能再要求补充信息”,每一步都是流失点。Account Creation API 把所有步骤压缩成一个系统 Sheet:信息预填、密码不需要、Passkey 自动创建。这个 UX 思路不仅适用于 passkey——任何需要快速注册的场景都应该参考”预填 + 集中确认”的模式。
Session 里还强调了一个最佳实践:App 启动时用 preferImmediatelyAvailableCredentials 选项检查是否有已有凭证。用户在 iPad 上第一次打开 App,直接弹出 passkey 登录提示——因为他之前在 iPhone 上注册过,passkey 自动同步了。这种”无感登录”体验是密码永远做不到的。
Signal API 的生态意义
Signal API 看起来只是”通知凭证管理器数据变了”,但它的生态意义更大。之前用户在 App 里改了用户名,凭证管理器里还是旧的——登录时看到的标签和实际不一致,容易搞混。现在通过 reportPublicKeyCredentialUpdate,凭证管理器实时同步。更进一步的 reportUnusedPasswordCredential 告诉凭证管理器”这个账户已经不需要密码了”,凭证管理器可以把密码标记为可删除。
这些信号 API 在 Web 端也有对应实现(signalCurrentUserDetails、signalAllAcceptedCredentials),意味着 App 和网站的凭证管理体验可以保持一致。
Well-known 端点的标准化
/.well-known/passkey-endpoints 是一个跨凭证管理器的标准。不管用户用的是系统密码 App 还是 1Password,都能读取同一个端点来发现你的 passkey 注册页面。这意味着你只需要在服务端实现一次,所有凭证管理器都能获益。响应必须是 200 OK + application/json,不能重定向——这个细节容易踩坑。
代码片段
Account Creation API 核心代码
func signUp() async {
let provider = ASCredentialIdentityProvider()
let request = provider.createPasskeyRegistrationRequest(
acceptedContactIdentifiers: [.email],
shouldRequestName: true,
relyingPartyIdentifier: "example.com",
challenge: fetchChallengeFromServer(),
userID: generateUserID()
)
do {
let controller = ASAuthorizationController(authorizationRequests: [request])
let result = try await controller.perform()
// 获取联系标识、姓名和 passkey
let contactID = result.contactIdentifier
let name = result.name
let passkey = result.passkey
// 在服务端创建账户
await createAccount(name: name, email: contactID, passkey: passkey)
} catch ASCredentialError.preferSignInWithApple {
// 已有 Apple 登录账户,发起 Sign in with Apple
try? await signInWithApple()
} catch {
// 展示传统注册表单
showCustomSignUpForm()
}
}
坑:challenge 必须是服务端生成的一次性值。客户端生成 challenge 会完全破坏安全性。
Automatic Passkey Upgrade
func attemptPasskeyUpgrade(account: Account) async {
guard !account.hasPasskey else { return }
let request = ASAuthorizationPlatformPublicKeyCredentialProvider(
relyingPartyIdentifier: "example.com"
).createCredentialRegistrationRequest(
challenge: fetchChallenge(),
name: account.username,
userID: account.userID
)
request.style = .conditional // 关键:静默模式
do {
let controller = ASAuthorizationController(authorizationRequests: [request])
let result = try await controller.perform()
await savePasskeyOnServer(result.credential)
} catch {
// 静默失败,不需要处理
// 下次密码登录时会再次尝试
}
}
坑:conditional style 在任何前置条件不满足时都静默失败——包括设备未配置 passcode、用户刚登录时未使用密码、凭证管理器不可用等。不要对这个失败做 UI 提示。
最佳实践
Account Creation API 应该作为新用户注册的首选路径。当它失败(deviceNotConfiguredForPasskeyCreation 或 canceled)时,降级到传统注册表单。不要反过来——先展示表单再建议 passkey,那样会失去速度优势。
Passkey 吊销后,调用 reportAllAcceptedPublicKeyCredentials 传入仍然有效的 credential ID 集合。凭证管理器会删除不在集合里的 passkey。建议每次登录后也周期性调用这个方法做健康检查。
对于还在用密码的已有用户,把 automatic upgrade 设成每次密码登录都尝试。条件不满足就静默跳过,没有任何成本。一旦成功,用户下次登录就能用 passkey,体验质的飞跃。
还有什么值得关注
- 2025 年 FIDO Alliance 的调查显示 69% 的受访者至少有一个 passkey,Google 数据显示 passkey 登录成功率是密码的 4 倍,TikTok 观察到 97% 的 passkey 登录成功率。
- passkey 的用户名标签是纯本地数据,不会在认证时发给服务端——用户可以随便改不影响功能。
- UIRequiresFullscreen Info.plist key 已废弃,下一个 major 版本会忽略——和 passkey 无关但值得注意。
- 凭证迁移使用 FIDO Alliance 协作制定的数据 schema,覆盖 passkey、密码、验证码等多种凭证类型。