Passkey

通行密钥是一种安全的、无密码认证方法,使用加密密钥对,由 WebAuthn 和 FIDO2 标准支持,在 Web 浏览器中可用。它们用唯一的密钥对替换密码:私钥存储在用户设备上,公钥与网站共享。用户可以使用生物识别、PIN 或安全密钥登录,提供强大的、抗钓鱼的认证,而无需传统密码。

通行密钥插件的实现由 SimpleWebAuthn 在幕后提供支持。

安装

将插件添加到您的认证配置

要将通行密钥插件添加到您的认证配置中,您需要导入插件并将其传递到认证实例的 plugins 选项。

选项

rpID:您的网站的唯一标识符。对于本地开发,'localhost' 是可以的

rpName:您的网站的人类可读标题

origin:注册和认证应发生的 URL。http://localhosthttp://localhost:PORT 也是有效的。不要包含任何尾随的 /

authenticatorSelection:允许自定义 WebAuthn 认证器选择标准。如果未指定,则使用默认设置。

  • authenticatorAttachment:指定认证器类型
    • platform:认证器附加到平台(例如,指纹阅读器)
    • cross-platform:认证器未附加到平台(例如,安全密钥)
    • 默认:not set(允许平台和跨平台两种,优先平台)
  • residentKey:确定凭据存储行为。
    • required:用户必须在认证器上存储凭据(最高安全性)
    • preferred:鼓励凭据存储但非强制
    • discouraged:无需凭据存储(最快体验)
    • 默认:preferred
  • userVerification:控制认证期间的生物识别/PIN 验证:
    • required:用户必须验证身份(最高安全性)
    • preferred:鼓励验证但非强制
    • discouraged:无需验证(最快体验)
    • 默认:preferred
auth.ts
import { betterAuth } from "better-auth"
import { passkey } from "better-auth/plugins/passkey"

export const auth = betterAuth({
    plugins: [ 
        passkey(), 
    ], 
})

迁移数据库

运行迁移或生成架构,以向数据库添加必要的字段和表。

npx @better-auth/cli migrate
npx @better-auth/cli generate

请参阅 Schema 部分以手动添加字段。

添加客户端插件

auth-client.ts
import { createAuthClient } from "better-auth/client"
import { passkeyClient } from "better-auth/client/plugins"

export const authClient = createAuthClient({
    plugins: [ 
        passkeyClient() 
    ] 
})

使用方法

添加/注册通行密钥

要添加或注册通行密钥,请确保用户已认证,然后调用客户端提供的 passkey.addPasskey 函数。

POST
/passkey/add-passkey
const { data, error } = await authClient.passkey.addPasskey({    name: "example-passkey-name",    authenticatorAttachment: "cross-platform",});
PropDescriptionType
name?
用于标记正在注册的认证器账户的可选名称。如果未提供,将默认使用用户的电子邮件地址或用户 ID
string
authenticatorAttachment?
您还可以指定要注册的认证器类型。默认行为允许平台和跨平台通行密钥
"platform" | "cross-platform"

使用通行密钥登录

要使用通行密钥登录,您可以使用 signIn.passkey 方法。这将提示用户使用其通行密钥登录。

POST
/sign-in/passkey
const { data, error } = await authClient.signIn.passkey({    email: "example@gmail.com", // required    autoFill: true,});
PropDescriptionType
email
要登录的用户电子邮件。
string
autoFill?
浏览器自动填充,即条件 UI。阅读更多:https://simplewebauthn.dev/docs/packages/browser#browser-autofill-aka-conditional-ui
boolean

示例用法

// 带有认证后重定向
await authClient.signIn.passkey({
    email: "user@example.com",
    autoFill: true,
    fetchOptions: {
        onSuccess(context) {
            // 认证成功后重定向到仪表板
            window.location.href = "/dashboard";
        },
        onError(context) {
            // 处理认证错误
            console.error("Authentication failed:", context.error.message);
        }
    }
});

列出通行密钥

您可以通过调用 passkey.listUserPasskeys 来列出认证用户的所有通行密钥:

GET
/passkey/list-user-passkeys
const { data: passkeys, error } = await authClient.passkey.listUserPasskeys();

删除通行密钥

您可以通过调用 passkey.delete 并提供通行密钥 ID 来删除通行密钥。

POST
/passkey/delete-passkey
const { data, error } = await authClient.passkey.deletePasskey({    id: "some-passkey-id", // required});
PropDescriptionType
id
要删除的通行密钥 ID。
string

更新通行密钥名称

POST
/passkey/update-passkey
const { data, error } = await authClient.passkey.updatePasskey({    id: "id of passkey", // required    name: "my-new-passkey-name", // required});
PropDescriptionType
id
要更新的通行密钥 ID。
string
name
将通行密钥更新为的新名称。
string

条件 UI

该插件支持条件 UI,这允许浏览器如果用户已注册通行密钥,则自动填充通行密钥。

条件 UI 工作的两个要求:

更新输入字段

autocomplete 属性添加到您的输入字段,并将其值设置为 webauthn。您可以向多个输入字段添加此属性,但至少需要一个以使条件 UI 工作。

webauthn 值还应是 autocomplete 属性的最后一个条目。

<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">

预加载通行密钥

当您的组件挂载时,您可以通过调用 authClient.signIn.passkey 方法并将 autoFill 选项设置为 true 来预加载用户的通行密钥。

为了防止不必要的调用,我们还将添加一个检查,以查看浏览器是否支持条件 UI。

useEffect(() => {
   if (!PublicKeyCredential.isConditionalMediationAvailable ||
       !PublicKeyCredential.isConditionalMediationAvailable()) {
     return;
   }

  void authClient.signIn.passkey({ autoFill: true })
}, [])

根据浏览器不同,将出现一个提示来自动填充通行密钥。如果用户有多个通行密钥,他们可以选择要使用的那个。

某些浏览器还要求用户首先与输入字段交互,然后自动填充提示才会出现。

调试

要测试您的通行密钥实现,您可以使用 emulated authenticators。这样,您可以测试注册和登录过程,而无需拥有物理设备。

架构

该插件需要在数据库中创建一个新表来存储通行密钥数据。

表名:passkey

Field NameTypeKeyDescription
idstring每个通行密钥的唯一标识符
namestring通行密钥的名称
publicKeystring-通行密钥的公钥
userIdstring用户的 ID
credentialIDstring-已注册凭据的唯一标识符
counternumber-通行密钥的计数器
deviceTypestring-用于注册通行密钥的设备类型
backedUpboolean-通行密钥是否已备份
transportsstring-用于注册通行密钥的传输方式
createdAtDate-通行密钥创建的时间
aaguidstring认证器的证明 GUID,表示认证器类型

选项

rpID:您的网站的唯一标识符。对于本地开发,'localhost' 是可以的。

rpName:您的网站的人类可读标题。

origin:注册和认证应发生的 URL。http://localhosthttp://localhost:PORT 也是有效的。请勿包含任何尾随 /。

authenticatorSelection:允许自定义 WebAuthn 认证器选择标准。如果未指定,则允许平台和跨平台认证器,并为 residentKeyuserVerification 使用 preferred 设置。

aaguid:(可选)认证器证明 GUID。这是通行密钥提供程序(设备或认证器类型)的唯一标识符,可用于识别注册或认证期间使用的通行密钥设备类型。

On this page