Get your free and exclusive +45-page Authentication Analytics Whitepaper
返回概览

开发者通行密钥速查表

关于 WebAuthn 和实施通行密钥的开发者指南。下载 PDF 格式的速查表,或者在此网站一站式获取所有信息。

Blog-Post-Author

Lukas R.

创建: 2024年3月6日

更新: 2026年7月3日

开发者通行密钥速查表

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

免费下载#

免费下载完整的通行密钥速查表并获取所有技术解析。

  • ✅ 已有超过 4,000 次下载
  • ✅ 应 Ally、Kmart、Octopus Energy 和 Stanford CS 开发团队的要求
  • ✅ 没有营销套话 - 只有技术干货

终极通行密钥开发者指南

下载通行密钥速查表

获取面向开发者的通行密钥参考指南,涵盖平台支持、浏览器行为、用户体验最佳实践和集成提示。

下载通行密钥速查表

免费下载通行密钥速查表

关键事实
  • 通行密钥身份验证使用两个流程:注册(证明)和登录(断言),每个流程都需要一个由服务器生成的、由身份验证器签名的随机质询。
  • PublicKeyCredentialCreationOptions 管理通行密钥注册,而 PublicKeyCredentialRequestOptions 管理登录。这两个对象均在服务器端生成,并包含供身份验证器签名的质询。
  • Conditional UI 将可用的通行密钥显示为自动填充建议,但这需要可发现凭据(常驻密钥),并且并非在所有操作系统和浏览器组合中都受支持。
  • 依赖方 ID (rpID) 将通行密钥绑定到域:仅当 URL 与 rpID 匹配或为其非公共后缀子域时,身份验证才会成功。
  • 通行密钥使用 COSE 算法生成密钥,具体算法记录在证明对象的 parsedCredentialPublicKey 属性中。

1. WebAuthn 流程#

使用通行密钥的身份验证基于两个过程(也称为流程):注册(也称为证明阶段)和登录(也称为断言阶段)。
每个阶段都需要一个由服务器生成的随机质询,该质询由身份验证器签名后发送回 WebAuthn 服务器以验证用户身份。

Debugger Icon

在 Passkeys Debugger 中体验 passkey 流程。

免费试用

1.1 注册(证明)#

注册流程使用两个核心对象:PublicKeyCredentialCreationOptions 和证明 (attestation)。

1.2 登录(断言)#

登录流程使用两个核心对象:PublicKeyCredentialRequestOptions 和断言 (assertion)。

StateOfPasskeys Icon

查看实际有多少人在使用 passkeys。

查看采用数据

2. 重要对象#

对于使用通行密钥的注册和登录,主要有四个对象:

  • PublicKeyCredentialCreationOptions
  • PublicKeyCredentialRequestOptions
  • 证明 (attestation)
  • 断言 (assertion)

本节还将解释 authenticatorSelection 对象,该对象在 PublicKeyCredentialCreationOptions 中使用。

Igor Gjorgjioski Testimonial

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

2.1 公钥凭据创建选项 (Public Key Credential Creation Options)#

PublicKeyCredentialCreationOptions 是证明阶段(注册)的核心对象。它由 WebAuthn 服务器创建并返回。

{ "PublicKeyCredentialCreationOptions": { "rp": { "id": "passkeys.eu", "name": "Corbado Passkeys Demo" }, "user": { "displayName": "john.doe", "id": "dXNyLZ….DU10Tc", "name": "john@doe.com" }, "challenge": "888fix4Bus...pHHr3Y", "pubKeyCredParams": [ { "alg": -7, "type": "public-key" }, { "alg": -257, "type": "public-key" } ], "excludeCredentials": [], "authenticatorSelection": { "authenticatorAttachment": "platform", "residentKey": "required", "userVerification": "required" }, "attestation": "none", "extensions": {} } }

该对象包含以下属性:

  • rp: 标识依赖方(即寻求对用户进行身份验证的服务器),请参阅第 4.2 依赖方 ID (rpID) 节。
  • user: 包含有关请求证明的用户帐户的数据。ID 是依赖方选择的字节序列,不得包含个人信息。用户名或电子邮件地址保存在 name 或 displayName 属性中。在第 4.1 数据库架构 节中了解更多信息。
  • challenge: 需要由身份验证器签名的随机生成的 base64URL 编码的 BufferSource。
  • pubKeyCredParams: 要创建的凭据的指定属性,通常是支持的算法。
  • timeout: 客户端等待调用完成的可选时间(以毫秒为单位)。
  • excludeCredentials: 用于限制在一台设备上创建多个通行密钥的可选凭据列表。
  • authenticatorSelection: 该方法所用身份验证器的可选选择,例如是否需要 residentKey。请参阅 2.5 authenticatorSelection
  • attestation: 可用于请求将证明对象以特定形式传递给依赖方。可能的值为 none(默认)、indirect、direct 和 enterprise。
  • extensions: 针对其他处理(例如特定返回值)的可选请求。例如:
    • credProbs 请求有关创建的凭据是否可发现的信息
    • prf 允许依赖方使用与凭据关联的伪随机函数 (PRF) 的输出
Substack Icon

订阅我们的 Passkeys Substack,获取最新消息。

订阅

2.2 公钥凭据请求选项 (Public Key Credential Request Options)#

PublicKeyCredentialRequestOptions 是断言阶段(登录)的核心对象。它由 WebAuthn 服务器创建并返回。

{ "publicKeyCredentialRequestOptions": { "challenge": "pT7HMA-…dFPHk", "timeout": 500, "rpId": "passkeys.eu", "userVerification": "preferred", "allowCredentials": [], "extensions": [] } }

该对象包含以下属性:

  • challenge、timeout、extensions: 请参阅上文
  • rpId: 断言请求的依赖方的标识符,请参阅第 4.2 依赖方 ID (rpID) 节。
  • allowCredentials: 允许用于身份验证的可选凭据列表,按降序指示调用者的偏好。该列表将填充 PublicKeyCredentialDescriptors。
  • userVerification: 用于指定操作期间用户验证要求的可选值。可能的值为 preferred(默认)、required 或 discouraged。

2.3 证明 (Attestation)#

在证明/注册流程中,身份验证器会返回此注册响应。您可以在 Passkeys Debugger 中自行尝试。

{ "authenticatorAttachment": "platform", "id": "JKZbixUfKN_aZtimefYT-OjH5dw", "rawId": "JKZbixUfKN_aZtimefYT-OjH5dw", "response": { "attestationObject": { "fmt": "none", "attStmt": {}, "authData": { "rpIdHash": "PpZrl-Wqt-OFfBpyy2SraN1m7LT0GZORwGA7-6ujYkM", "flags": { "userPresent": true, "userVerified": true, "backupEligible": true, "backupStatus": true, "attestedData": true, "extensionData": false }, "counter": 0, "aaguid": { "raw": "fbfc3007-154e-4ecc-8c0b-6e020557d7bd", "name": "iCloud Keychain" }, "credentialID": "JKZbixUfKN_aZtimefYT-OjH5dw", "credentialPublicKey": "pQECAyYgASFYIPWLalDzyxIDmAADvfK8iNM5To50kh7TyPH-teEz8RMdIlgg3D7bPIWQJ8z-WFn3zdYZzJw9c7mhPdmflQqD9vV7efA", "parsedCredentialPublicKey": { "keyType": "EC2 (2)", "algorithm": "ES256 (-7)", "curve": 1, "x": "9YtqUPPLEgOYAAO98ryI0zlOjnSSHtPI8f614TPxEx0", "y": "3D7bPIWQJ8z-WFn3zdYZzJw9c7mhPdmflQqD9vV7efA" } } }, "clientDataJSON": { "type": "webauthn.create", "challenge": "k2p6f-upzP_hc6NZvmMAxiI0VSTeQIeXXVRGW62LTj0", "origin": "https://www.passkeys-debugger.io", "crossOrigin": false }, "transports": ["hybrid", "internal"], "authenticatorData": "PpZrl-Wqt-OFfBpyy2SraN1m7LT0GZORwGA7-6ujYkNdAAAAAPv8MAcVTk7MjAtuAgVX170AFCSmW4sVHyjf2mbYpnn2E_jox-XcpQECAyYgASFYIPWLalDzyxIDmAADvfK8iNM5To50kh7TyPH-teEz8RMdIlgg3D7bPIWQJ8z-WFn3zdYZzJw9c7mhPdmflQqD9vV7efA", "publicKey": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9YtqUPPLEgOYAAO98ryI0zlOjnSSHtPI8f614TPxEx3cPts8hZAnzP5YWffN1hnMnD1zuaE92Z-VCoP29Xt58A", "publicKeyAlgorithm": -7 }, "type": "public-key", "clientExtensionResults": {} }

证明包含一些重要组件,如 attestationObjectalgorithmtransport 标志。

2.3.1 attestationObject#

摘自 W3C 的 WebAuthn 规范

attestationObject 是一个 CBOR 编码对象,其中包含有关新创建的凭据、公钥和其他相关信息的数据:

  • 对于通行密钥,fmt 通常评估为 "none"
  • attStmt 对于通行密钥为空,对于其他身份验证器(例如硬件安全密钥)则会填充内容
  • authData 是一个包含以下数据的缓冲区:

详细了解扩展

算法 (algorithm)#

通行密钥是使用 COSE 算法生成的,在证明对象的 parsedCredentialPublicKey 的 algorithm 属性中指明了所使用的算法。
以下是相关的 COSE 算法的概述:

2.3.2 传输 (transport)#

transports 属性表示身份验证器可通过哪些机制与客户端通信。一些常见的示例值组合包括:

  • "transports": ["internal","hybrid"]: 通行密钥可以从平台身份验证器(例如 Face ID、Touch ID、Windows Hello)使用,或者通过跨设备身份验证(使用二维码和蓝牙)使用。
  • "transports": ["internal"]: 通行密钥只能从平台身份验证器(例如 Face ID、Touch ID、Windows Hello)使用。
  • 未设置 "transports" 属性: 默认行为,不给出任何指示。

2.4 断言 (Assertion)#

断言/登录流程中,身份验证器会返回此登录响应。您可以在 Passkeys Debugger 中自行尝试。

{ "id": "JKZbixUfKN_aZtimefYT-OjH5dw", "rawId": "JKZbixUfKN_aZtimefYT-OjH5dw", "type": "public-key", "authenticatorAttachment": "platform", "response": { "authenticatorData": { "rpIdHash": "PpZrl-Wqt-OFfBpyy2SraN1m7LT0GZORwGA7-6ujYkM", "flags": { "userPresent": true, "userVerified": true, "backupEligible": true, "backupStatus": true, "attestedData": false, "extensionData": false }, "counter": 0 }, "clientDataJSON": { "type": "webauthn.get", "challenge": "GCVkITWbe2l2dttsn_DgJYvH9QPHPDo0ygWgcgI6B7U", "origin": "https://www.passkeys-debugger.io", "crossOrigin": false, "other_keys_can_be_added_here": "do not compare clientDataJSON against a template. See https://goo.gl/yabPex" }, "signature": "MEQCIA-orC8N2KKWOxyY17BWP8lB-Be5to9btXRnJZf2SLhXAiBGxJe5Eu5LwOTbsyzAYmIXHOhlC3pN7s7Q1fRLvEW57g", "userHandle": "_FKz1uwqmR_3yGq6hJntzoIFwFC_d1u_53YRELh0KlE" } }

断言包含一些重要组件,如标志 (flags)、签名 (signature) 和 userHandle。

2.4.1 标志 (flags)#

以下是最重要标志及其组合的概述:

2.4.2 签名 (signature)#

签名用于验证尝试登录的用户是否确实拥有私钥。签名是通过将 authenticatorData 和 clientDataHash(即 ClientDataJSON 的 SHA-256 版本)拼接在一起,并使用私钥(在身份验证器中)对结果进行签名来创建的。若要使用公钥进行验证,我们也拼接 authenticatorData 和 clientDataHash。如果验证结果返回 true,则身份验证成功。

2.4.3 userHandle#

userHandle 是实际的 user_id。在第 4.1 数据库架构 节中了解有关 user_id 的更多信息。

2.5 authenticatorSelection#

authenticatorSelection 对象允许服务器指示身份验证器和凭据创建的设置,包括以下值:

2.5.1 authenticatorAttachment#

  • Platform: 身份验证器连接到客户端的平台,因此不可移除。
  • Cross-platform: 身份验证器未绑定到客户端的平台,可以在多台设备上使用。

2.5.2 residentKey#

  • Required: 身份验证器必须创建一个常驻密钥(如果不可能,则操作应该失败)。
  • Preferred: 身份验证器应尝试创建一个常驻密钥(如果不可能,则应创建一个非常驻密钥)。
  • Discouraged: 身份验证器必须创建一个非常驻密钥(如果不可能,则操作应失败)。

常驻密钥(也称为可发现凭据): 常驻密钥存储在身份验证器上,并在身份验证期间检索。以此方式,客户端可以发现可能的密钥列表,这就是 [Conditional UI](/blog/user-transition-passkeys-> conditional-ui) 需要常驻密钥的原因。 非常驻密钥(也称为不可发现凭据): 如果是非常驻密钥,凭据 ID 将存储在服务器上,并在身份验证期间提供。凭据 ID 是一种不透明标识符,其内部结构因实施而异——身份验证器可以直接存储私钥、使用加密的密钥包装,或从内部机密中派生密钥。确切的机制因身份验证器实现而异。

2.5.3 userVerification#

  • Required: 操作应验证用户。
  • Preferred: 操作应验证用户,但也可以不验证继续进行(标准选项)。
  • Discouraged: 操作不应验证用户。

**警告:**如果设置为“Preferred”,则用户或其设备可以跳过身份验证过程中的用户验证(阅读此文章了解更多信息)。

3. Conditional UI (条件 UI)#

当用户已向依赖方注册常驻密钥时,Conditional UI(通行密钥自动填充)会在选择下拉列表中向用户显示可用的通行密钥。它提高了通行密钥的可用性,但需要额外的开发工作,并且并非在所有操作系统/浏览器组合中可用。

3.1 带有 Conditional UI 的登录流#

像常规登录一样,Conditional UI 也使用对象 PublicKeyCredentialRequestOptions 和断言

3.2 设备兼容性#

Conditional UI 尚未在所有操作系统和浏览器组合上可用。以下是当前浏览器覆盖范围的概述(2024 年 3 月):

如需最新概述,请访问此网站

3.3 代码示例#

3.3.1 Conditional UI 方法#

Conditional 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 { // 从 WebAuthn 服务器检索请求选项(包括质询) 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>

3.3.2 浏览器兼容性检查#

Conditional UI 仅适用于常驻密钥/可发现凭据
建议提供不同的服务器端点以启动 Conditional UI 登录。
客户端需要满足多项要求:

  • 浏览器需要支持 Conditional UI(请参阅 3.2 设备兼容性)。
  • 必须启用 JavaScript 并且网页必须提供 HTML 输入字段。
  • 超时参数应被忽略。

为避免错误,服务器首先应使用以下函数测试客户端可用性: 在真实流量中,检测和生命周期问题通常表现为 NotAllowedErrorAbortError。使用本指南以区分预期错误与意外错误,包括原生凭据管理器通行密钥错误。

// 来源:https://developer.mozilla.org/en-US/docs/Web/API/PublicKeyCredential/isConditionalMediationAvailable#examples // `window.PublicKeyCredential` 可用意味着 WebAuthn 可用。 if (window.PublicKeyCredential && PublicKeyCredential.isConditionalMediationAvailable) { // 检查条件中介是否可用。 const isCMA = await PublicKeyCredential.isConditionalMediationAvailable(); if (isCMA) { // 调用 WebAuthn 身份验证启动端点 let options = await WebAuthnClient.getPublicKeyRequestOptions(); const credential = await navigator.credentials.get({ publicKey: options.publicKeyCredentialRequestOptions, mediation: "conditional", }); /* ... */ } }

3.3.3 输入字段中的自动完成令牌#

输入字段应接收 HTML 自动填充令牌,该令牌向客户端发出将通行密钥填充到进行中请求的信号。除了通行密钥外,自动填充令牌还可以与现有令牌搭配使用,例如用户名和密码:

  • autocomplete="username webauthn": 除了显示通行密钥外,这还会建议用户名自动填充。
  • autocomplete="current-password webauthn": 除了显示通行密钥外,这还会进一步提示密码自动填充。
<label for="name">用户名:</label> <input type="text" name="name" autocomplete="username webauthn" /> <label for="password">密码:</label> <input type="password" name="password" autocomplete="current-password webauthn" />

4. WebAuthn 服务器#

4.1 数据库架构#

WebAuthn 服务器没有强制或标准化的数据库架构。但是,此示例数据库架构可用于存储所需信息并提供 WebAuthn 服务器的所有功能:

加粗属性对于最小可行实现是强制性的,而其他属性仅对于可选但有用的功能才是必需的。

4.1.1 身份验证相关数据#

  • 凭据 ID: 这是在通行密钥注册期间由身份验证器生成的唯一 ID。应使用它来查找与通行密钥关联的实际用户帐户。此外,应该比较 userHandle(来自 user_id)以验证用于身份验证的帐户。请勿使用 user.name 属性进行比较,因为它可能会随时间改变。
  • 用户 ID (user_id): 由依赖方指定的用于表示其系统中用户帐户的唯一 ID。它作为 userHandle 在 assertion 对象中返回。

4.1.2 用于显示和选择通行密钥的元数据:#

  • 用户显示名称 (user.displayName): 用户友好的、可读的名称,通常是用户的全名。它会显示给用户,但不在身份验证期间使用。

  • 用户名 (user.name): 唯一的、可读的名称,通常是电子邮件地址或用户名。它可以显示给用户,但在身份验证期间不使用。

4.2 依赖方 ID (rpId)#

依赖方 ID (rpID) 是存储在通行密钥中的域,确保通行密钥仅适用于正确的域(浏览器 URL,请参阅本文了解原生应用程序)。在身份验证期间,将针对浏览器 URL 检查 rpID,并且仅在以下两种情况下允许:

  1. URL 与 rpId 完全匹配,或者
  2. URL 是与 rpId 匹配的子域,并且父域不在公共后缀列表中

以下是(不)允许的组合示例:

5. 帮助网站和工具#

以下是用于实施通行密钥的有用工具和网站列表。

对于技术实现以外优化通行密钥用户体验的策略,请参阅我们关于通行密钥创建最佳实践和通行密钥登录最佳实践的指南。

如果只想用几行代码在任何应用程序中实施通行密钥,也可以使用 Corbado Complete(用于新应用程序)或 Corbado Connect(用于现有应用程序)

Corbado

关于 Corbado

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 专家交谈

常见问题#

如何在我的 Web 应用程序中实现用于通行密钥自动填充的 Conditional UI?#

Conditional UI 需要在启动身份验证前通过 PublicKeyCredential.isConditionalMediationAvailable() 检查浏览器支持。输入字段必须包含 autocomplete="username webauthn" HTML 令牌,并且用户必须已注册常驻密钥(可发现凭据)。建议使用单独的服务器端点来处理 Conditional UI 登录流程。

要支持 WebAuthn 身份验证,我需要在数据库中存储的最少数据是什么?#

至少需要存储身份验证器在注册期间生成的凭据 ID,以及用户 ID (user_id),它作为 userHandle 在断言对象中返回。使用凭据 ID 查找关联的用户帐户,并比较 userHandle 以验证身份验证。避免使用 user.name 进行比较,因为它可能会随时间变化。

WebAuthn 中常驻密钥和非常驻密钥的区别是什么?#

常驻密钥(可发现凭据)存储在身份验证器本身,并在身份验证期间检索,这是 Conditional UI 正常工作所必需的。非常驻密钥将凭据 ID 存储在服务器上,并在身份验证期间将其发送给身份验证器。authenticatorSelection 中的 residentKey 字段使用“required”、“preferred”或“discouraged”等值来控制此行为。

userVerification 是如何工作的,将其设置为 preferred 的风险是什么?#

userVerification 字段控制身份验证器是否必须在登录期间验证用户,接受值为“required”、“preferred”(默认)或“discouraged”。当设置为“preferred”时,用户或其设备可以在身份验证过程中完全跳过验证,这可能会降低安全性。将其设置为“required”可确保始终在身份验证完成之前进行验证。

了解 Corbado 如何适配你的 passkey 推广和现有身份验证栈。

探索 Console

分享本文


LinkedInTwitterFacebook