本页由自动翻译生成。请阅读英文原文 此处.

Passkeys 速查表. 面向 passkey 项目的实用指南、推广模式和 KPI。
isConditionalMediationAvailable(),以防止在不支持的浏览器或设备上出现用户可见的错误。autocomplete="username webauthn" 令牌向浏览器发出信号,在自动填充下拉列表中将通行密钥与密码建议一起显示。navigator.credentials.get() 调用中设置 mediation: "conditional" 会激活通行密钥自动填充,而不会用阻塞式模式对话框打断用户。AbortController,因为自动填充下拉列表与模式提示不同,没有内置的取消按钮。随着通行密钥(以及底层的 WebAuthn 协议)的快速普及,对许多用户来说,身份验证变得更加安全和友好。通行密钥最突出的进步之一是集成了条件 UI(Conditional UI),通常被称为“通行密钥自动填充(passkey autofill)”或条件中介(Conditional Mediation)(在下文中我们将继续使用条件 UI 这个术语)。
尽管它最近才被引入并且浏览器正在不断采用,但在条件 UI 的技术文档和实现建议方面存在明显的空白。本文旨在通过解释什么是条件 UI、它是如何工作的以及如何解决其实现过程中的常见挑战,来弥补这一空白。
条件 UI 代表了通行密钥 / WebAuthn 登录过程的一种新模式。它只在用户拥有存储在其设备(如笔记本电脑、智能手机)的身份验证器中且在该依赖方(在线服务)注册的可发现凭据(常驻密钥,通行密钥的一种)时,才有选择地在用户界面 (UI) 中显示通行密钥。通行密钥显示在一个与自动填充密码混合的选择下拉列表中,提供了传统密码系统和高级通行密钥身份验证之间的无缝过渡,因为用户在相同的上下文中看到两者。这种智能的方法确保用户不会被不必要的选项淹没,并且可以更顺畅地浏览登录过程。
Igor Gjorgjioski
Head of Digital Channels & Platform Enablement, VicRoads
We hit 80% mobile passkey activation across 5M+ users without replacing our IDP.
See how VicRoads scaled passkeys to 5M+ users — alongside their existing IDP.
Read the case study条件 UI 的基础建立在三大支柱之上:
订阅我们的 Passkeys Substack,获取最新消息。
下面,我们将逐步分析整个条件 UI 流程的各个步骤:
通常,条件 UI 的流程可以分为两个阶段。在页面加载阶段,条件 UI 逻辑在后台进行,而在用户操作阶段,用户必须主动执行某些操作。
isConditionalMediationAvailable() 函数来检测当前的浏览器/设备组合是否支持条件 UI。只有当响应为 true 时,进程才会继续,否则条件 UI 进程将被中止。mediation 属性设置为 conditional 的 credentials.get(),设备上本地身份验证的进程开始。通过遵循此流程,条件 UI 提供了无缝且用户友好的身份验证体验。
为了使条件 UI 正常工作,需要考虑一些一般方面:
加入我们的 Passkeys Community,获取更新和支持。
为了使条件 UI 在客户端工作,必须满足以下要求:
isConditionalMediationAvailable() 方法并检查条件 UI 的技术可用性(有关更多详细信息,请参见下文)。为了使条件 UI 正常工作,服务器端也必须满足一些要求:
自 2022 年底条件 UI 的正式推出和早期的测试版以来,我们一直在广泛地测试和使用它。下面,我们将与你分享在实现条件 UI 期间有所帮助的实用技巧。
在 Passkeys Debugger 中体验 passkey 流程。
条件 UI 方法的完整、极简的代码示例如下所示:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Conditional UI</title> </head> <body> <input type="text" id="username" autocomplete="username webauthn" /> <script> async function passkeyLogin() { try { // retrieve the request options (incl. the challenge) from the WebAuthn server let options = await WebAuthnClient.getPublicKeyRequestOptions(); const credential = await navigator.credentials.get({ publicKey: options.publicKeyCredentialRequestOptions, mediation: "conditional", }); const userData = await WebAuthnClient.sendSignedChallenge(credential); window.location.href = "/logged-in"; } catch (error) { console.log(error); } } passkeyLogin(); </script> </body> </html>
实现条件 UI 检测,以确保条件 UI 仅在当前设备/浏览器组合支持时才被使用。这应该在缺乏条件 UI 支持的情况下不会呈现用户可见的错误。在用户界面中合并 isConditionalMediationAvailable() 方法可以解决这个问题。如果支持条件 UI,则可以启动条件 UI 登录过程。
// source: https://developer.mozilla.org/en-US/docs/Web/API/PublicKeyCredential/isConditionalMediationAvailable#examples // Availability of `window.PublicKeyCredential` means WebAuthn is usable. if (window.PublicKeyCredential && PublicKeyCredential.isConditionalMediationAvailable) { // Check if conditional mediation is available. const isCMA = await PublicKeyCredential.isConditionalMediationAvailable(); if (isCMA) { // Call WebAuthn authentication start endpoint let options = await WebAuthnClient.getPublicKeyRequestOptions(); const credential = await navigator.credentials.get({ publicKey: options.publicKeyCredentialRequestOptions, mediation: "conditional", }); /* ... */ } }
输入字段应该接收一个 webauthn HTML 自动填充令牌。这向客户端发出信号,将通行密钥填充到正在进行的请求中。除了通行密钥,还可能展示其他自动填充值。这些自动填充令牌可以与其他现有令牌配对,例如:
autocomplete="username webauthn":除了显示通行密钥外,还会建议用户名自动填充。autocomplete="current-password webauthn":除了显示通行密钥外,还会进一步提示密码自动填充。<label for="name">Username:</label> <input type="text" name="name" autocomplete="username webauthn" /> <label for="password">Password:</label> <input type="password" name="password" autocomplete="current-password webauthn" />
了解更多细节,我们建议阅读此博客文章,其中提供了有关通行密钥和密码的自动填充 / 自动完成令牌的更多详细信息。
要在收到 PublicKeyCredentialRequestOptions 对象后检索可用的通行密钥,应调用 navigator.credentials.get() 函数(它同时提供通行密钥和密码)。PublicKeyCredentialRequestOptions 对象需要将 mediation 参数设置为 conditional 以激活客户端上的条件 UI。对于你想要一个模式通行密钥提示的情况,请参见 immediate mediation。
const credential = await navigator.credentials.get({ publicKey: options.publicKeyCredentialRequestOptions, mediation: "conditional", });
如果没有可用的通行密钥,或者用户忽略了建议的通行密钥并输入了他们的电子邮件,则条件 UI 流程将停止。这强调了始终通过模式对话框支持标准通行密钥 / WebAuthn 登录的重要性。
在这里需要强调的一个关键点是停止正在进行的条件 UI 请求的潜在需求。与模式体验相反,自动填充下拉列表缺少取消按钮。根据 WebAuthn 的设计,在任何给定时刻只能有一个活动的凭据请求正在进行中。WebAuthn 标准建议使用 AbortController来取消 WebAuthn 过程,这适用于常规和条件 UI 登录过程(有关详细信息,请参见此处)。
在生产遥测中,这种取消路径通常是预期的控制流结果,而不是系统故障。如果你看到大量的错误,在将它们视为回归之前,你需要根据操作类型和时间对预期与意外情况进行分类(参见 WebAuthn 错误)。
一旦用户登陆页面,条件 UI 登录过程就会被激活。首要任务应该是创建一个全局范围的 AbortController 对象。这将作为你的客户端终止自动填充请求的信号,特别是如果用户决定执行常规通行密钥登录过程的话。
请确保其他函数可以调用 AbortController,并在必须重新启动条件 UI 过程时将其重置。在 navigator.credentials.get() 调用中使用 signal 属性,合并你的 AbortController 信号作为其值。这向通行密钥 / WebAuthn 函数发出信号,如果信号被中止,必须停止该请求。切记每次触发条件 UI 时都要设置一个新的 AbortController。使用已经中止的 AbortController 将导致通行密钥 / WebAuthn 函数立即取消。其余步骤与常规通行密钥登录过程一致。在下面,你将看到所提到步骤的代码示例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Conditional UI</title> </head> <body> <input type="text" id="username" autocomplete="username webauthn" /> <script> async function passkeyLogin() { try { // retrieve the request options (incl. the challenge) from the WebAuthn server let options = await WebAuthnClient.getPublicKeyRequestOptions(); const credential = await navigator.credentials.get({ publicKey: options.publicKeyCredentialRequestOptions, mediation: "conditional", }); const userData = await WebAuthnClient.sendSignedChallenge(credential); window.location.href = "/logged-in"; } catch (error) { console.log(error); } } passkeyLogin(); </script> </body> </html>
在缺乏条件 UI 支持的情况下,引导用户进行常规通行密钥登录过程。为依赖硬件安全密钥(例如 YubiKeys)的用户或由于身份验证器限制而被迫使用非常驻密钥 / 不可发现凭据的用户提供此路径非常重要。
查看实际有多少人在使用 passkeys。
当你开发原生应用程序(例如针对 iOS 或 Android)时,条件 UI 也能工作。无论你是使用 Flutter、Kotlin 还是 Swift 进行原生开发,或者如果你决定采用 Chrome Custom Tabs (CCT) 或 SFSafariViewController 或 SFAuthenticationSession / ASWebAuthenticationSession,都没关系。两种方法都支持条件 UI。
通常,我们几乎没有找到有关如何为 iOS 应用添加条件 UI 支持的文档。然而,在我们的研究过程中,我们发现了向 iOS 应用添加条件 UI 支持的两种方式,因为用户体验也会有所不同。
类型 A:覆盖几乎整个屏幕的叠加层 / 弹出窗口
第一种类型 A 会显示一个跨越几乎整个屏幕的叠加层 / 弹出窗口。在这里,你将看到该依赖方的所有可用通行密钥。以这种方式实现条件 UI 的一个著名例子是 KAYAK。当用户打开正确的屏幕时,会自动弹出叠加层 / 弹出窗口。
类型 B:键盘自动填充
第二种类型 B 会在键盘的自动填充部分(这里通常也会建议自动填充密码)显示一个合适的通行密钥。点击建议的值将执行 Face ID 身份验证并让你登录。在 Corbado 开发者面板目前的 iOS 应用程序版本中,我们是以这种方式实现的(参见带有 WebAuthn 用户名的针对 <relying party ID> 消息使用通行密钥登录的提示)。要显示出来,用户需要点击进入输入字段:
当全新安装 iOS 时,键盘部分的通行密钥自动填充功能可能会出现问题,因为显然在后台进行了一些缓存操作,用于查找该依赖方的所有可用通行密钥。
点击建议通行密钥右侧的钥匙图标将进入 iOS 中众所周知的选择密码/通行密钥页面:
请注意,我们尚未找到官方文档,我们的见解基于我们的经验和假设,而不是具体证明的适当实现。
在 Android 系统中,关于条件 UI 的说明要清楚得多,因为只有一种利用 Android Credential Manager API(请参阅此处的文档)进行条件 UI / 通行密钥自动填充的类型。由于 Android 的提供商可能有所不同,请将 Credential Manager 通行密钥错误与纯浏览器的 WebAuthn 失败模式分开监控。
打开实现条件 UI 的页面会显示以下屏幕,在这里你可以找到不同的登录方式:
点击**更多保存的登录信息(More saved sign-ins)**将提供更多登录选项供选择(包括跨设备身份验证以及选择其他通行密钥同步平台,例如 Samsung Pass 或 1Password):
为了说明条件 UI 在最终用户面前的样子,我们添加了几张使用 https://passkeys.eu 的条件 UI 自动填充菜单截图。
在实时 demo 中试用 passkeys。
让我们来看看实际应用中的一些常见场景。
如果没有为站点保存通行密钥,根据浏览器和操作系统的不同,条件 UI 的行为将会有所不同。
在 macOS 的 Chrome 上,点击进入输入字段将显示一个空的自动填充下拉列表:
在 macOS 的 Safari 上,不显示下拉列表,仅在输入字段中显示一个不起眼的图标:
在 Android 或 iOS 上,仅当用户点击字段且操作系统找到匹配的凭据后,才会出现自动填充界面。
这种差异性是经过深思熟虑的,也是 WebAuthn 隐私模型的一部分:除非用户主动选择,否则网站无法检测到通行密钥是否存在。
如果用户安装了多个通行密钥提供商(例如 iCloud Keychain、Google Password Manager、1Password),浏览器或操作系统通常会默认使用用户的主要凭据管理器。
如需获取支持通行密钥的不同通行密钥提供商/凭据管理器列表,我们建议查看以下 GitHub 链接。
在 Android 上,Credential Manager 会暴露不同的提供商,如 Samsung Pass 或 1Password。
在 iOS 上,钥匙图标会打开来自各个源的完整通行密钥列表。
作为一款应用或网站,你无法控制使用哪种凭据管理器——操作系统会管理该选择以维护用户隐私。
通行密钥及其条件 UI / 通行密钥自动填充功能,提供了一种在线身份验证的新方法。随着我们向密码越来越被通行密钥取代的时代过渡,对强大且用户友好的过渡机制的需求是不可否认的。本文帮助了解了如何正确实现条件 UI(在过渡过程中有很大帮助)以及应特别注意哪些方面。
Corbado 是面向大规模运行 consumer 身份验证的 CIAM 团队的Authentication Intelligence Platform。我们让你看到 IDP 日志和通用 analytics 工具看不到的内容:哪些设备、操作系统版本、浏览器和 credential manager 支持 passkey,为什么注册没有转化为登录,WebAuthn 流程在哪里失败,以及什么时候操作系统或浏览器更新会悄悄破坏登录 — 而且无需替换 Okta、Auth0、Ping、Cognito 或你自有的 IDP。两款产品:Corbado Observe 提供 针对 passkey 及任何其他登录方式的 observability。Corbado Connect 提供 内置 analytics 的 managed passkey(与你的 IDP 并存)。VicRoads 通过 Corbado 为 500 万以上用户运行 passkey(passkey 激活率 +80%)。 与 Passkey 专家交谈 →
调用 PublicKeyCredential.isConditionalMediationAvailable() 并且仅在返回 true 时继续。这种检查可以防止在不支持的浏览器和设备组合上出现用户可见的错误。应在每次页面加载时,在调用带有 mediation: "conditional" 的 navigator.credentials.get() 之前对该方法进行评估。
身份验证器仅为常驻密钥(可发现凭据)存储用户特定数据,例如姓名和显示名称。非常驻密钥不保留此信息,因此自动填充菜单无法填充供用户选择的账户详细信息。
不同平台的行为各异。macOS 上的 Chrome 显示空的自动填充下拉列表,macOS 上的 Safari 仅在输入字段中显示一个不起眼的图标,而在 Android 或 iOS 上,只有当用户点击该字段后操作系统找到匹配的凭据时才会出现自动填充界面。这种差异性是有意的,并且是 WebAuthn 隐私模型的一部分:除非用户主动选择,否则网站无法检测到是否存在通行密钥。
创建一个全局作用域的 AbortController,并将其 signal 传递给 navigator.credentials.get()。当用户启动模式登录流程时,调用控制器上的 .abort()。每次条件 UI 重新启动时都必须实例化一个新的 AbortController,因为重复使用已中止的控制器会导致 WebAuthn 请求立即取消。
条件 UI 适用于原生 iOS 和 Android 应用程序。iOS 支持两种变体:全屏叠加层弹出窗口和键盘自动填充建议。Android 使用 Credential Manager API,它可以显示来自多个提供商(如 Samsung Pass 或 1Password)的通行密钥。
相关文章
目录