通行密钥
通行密钥(Passkeys)是一种安全、无需密码的身份验证方式,它利用加密密钥对,并得到 Web 浏览器中 WebAuthn 和 FIDO2 标准的支持。它通过唯一的密钥对替代传统密码:私钥存储在用户设备上,公钥则与网站共享。用户可通过生物识别、PIN 码或安全密钥登录,提供强大且防钓鱼的身份验证,无需依赖传统密码。
通行密钥插件的实现底层基于 SimpleWebAuthn。
安装
将插件添加到认证配置中
要将 passkey 插件添加到认证配置中,您需要导入该插件并将其传递给认证实例的 plugins
选项。
选项
rpID
: 您网站的唯一标识符。本地开发时可以使用 'localhost'
rpName
: 您网站的可读标题
origin
: 注册和认证应该发生的 URL。http://localhost
和 http://localhost:PORT
也是有效的。不要包含尾部斜杠 /
authenticatorSelection
: 允许自定义 WebAuthn 认证器选择标准。不指定则使用默认设置。
authenticatorAttachment
: 指定认证器类型platform
: 认证器附加到平台(例如指纹读取器)cross-platform
: 认证器不附加到平台(例如安全密钥)- 默认值:
not set
(允许平台和跨平台认证器,优先选择平台认证器)
residentKey
: 确定凭据存储行为。required
: 用户必须在认证器上存储凭据(最高安全性)preferred
: 鼓励凭据存储但不是强制性的discouraged
: 不需要凭据存储(最快体验)- 默认值:
preferred
userVerification
: 控制认证过程中的生物识别/PIN 验证:required
: 用户必须验证身份(最高安全性)preferred
: 鼓励验证但不是强制性的discouraged
: 不需要验证(最快体验)- 默认值:
preferred
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
请参阅模式部分以手动添加字段。
添加客户端插件
import { createAuthClient } from "better-auth/client"
import { passkeyClient } from "better-auth/client/plugins"
export const authClient = createAuthClient({
plugins: [
passkeyClient()
]
})
使用方法
添加/注册通行密钥
要添加或注册通行密钥,请确保用户已通过身份验证,然后调用客户端提供的 passkey.addPasskey
函数。
const { data, error } = await authClient.passkey.addPasskey({ name: "example-passkey-name", authenticatorAttachment: "cross-platform",});
属性 | 描述 | 类型 |
---|---|---|
name? | 用于标记正在注册的认证器账户的可选名称。如果未提供,将默认为用户的电子邮件地址或用户 ID | string |
authenticatorAttachment? | 您还可以指定要注册的认证器类型。默认行为允许同时使用平台和跨平台通行密钥 | "platform" | "cross-platform" |
使用通行密钥登录
要使用通行密钥登录,您可以使用 signIn.passkey
方法。这将提示用户使用其通行密钥登录。
const { data, error } = await authClient.signIn.passkey({ email: "example@gmail.com", // required autoFill: true, callbackURL: "/dashboard",});
属性 | 描述 | 类型 |
---|---|---|
email | 要登录的用户的电子邮件。 | string |
autoFill? | 浏览器自动填充,也称为条件 UI。了解更多:https://simplewebauthn.dev/docs/packages/browser#browser-autofill-aka-conditional-ui | boolean |
callbackURL? | 用户登录后重定向的 URL。 | string |
列出通行密钥
您可以通过调用 passkey.listUserPasskeys
来列出已认证用户的所有通行密钥:
const { data: passkeys, error } = await authClient.passkey.listUserPasskeys();
删除通行密钥
您可以通过调用 passkey.delete
并提供通行密钥 ID 来删除通行密钥。
const { data, error } = await authClient.passkey.deletePasskey({ id: "some-passkey-id", // required});
属性 | 描述 | 类型 |
---|---|---|
id | 要删除的通行密钥 ID。 | string |
更新通行密钥名称
const { data, error } = await authClient.passkey.updatePasskey({ id: "id of passkey", // required name: "my-new-passkey-name", // required});
属性 | 描述 | 类型 |
---|---|---|
id | 要更新的通行密钥 ID。 | string |
name | 通行密钥将更新为的新名称。 | string |
条件式 UI
该插件支持条件式 UI(Conditional UI),允许浏览器在用户已注册通行密钥时自动填充。
条件式 UI 需要满足两个要求:
更新输入字段
在输入字段中添加值为 webauthn
的 autocomplete
属性。您可以在多个输入字段中添加此属性,但至少需要一个才能使条件式 UI 正常工作。
webauthn
值应作为 autocomplete
属性的最后一个条目。
<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">
预加载通行密钥
当组件挂载时,您可以通过调用 authClient.signIn.passkey
方法并将 autoFill
选项设置为 true
来预加载用户的通行密钥。
为避免不必要的调用,我们还会添加检查以确认浏览器是否支持条件式 UI。
useEffect(() => {
if (!PublicKeyCredential.isConditionalMediationAvailable ||
!PublicKeyCredential.isConditionalMediationAvailable()) {
return;
}
void authClient.signIn.passkey({ autoFill: true })
}, [])
根据浏览器的不同,会出现自动填充通行密钥的提示。如果用户有多个通行密钥,他们可以选择要使用的那个。
某些浏览器还要求用户先与输入字段交互,然后才会显示自动填充提示。
调试
要测试您的通行密钥实现,您可以使用模拟认证器。这样,您无需拥有物理设备即可测试注册和登录流程。
数据库表结构
该插件需要在数据库中创建一个新表来存储通行密钥数据。
表名:passkey
字段名称 | 类型 | Key | 描述 |
---|---|---|---|
id | string | 每个通行密钥的唯一标识符 | |
name | string | 通行密钥的名称 | |
publicKey | string | - | 通行密钥的公钥 |
userId | string | 用户的ID | |
credentialID | string | - | 注册凭证的唯一标识符 |
counter | number | - | 通行密钥的计数器 |
deviceType | string | - | 用于注册通行密钥的设备类型 |
backedUp | boolean | - | 通行密钥是否已备份 |
transports | string | - | 用于注册通行密钥的传输方式 |
createdAt | Date | - | 通行密钥创建的时间 |
aaguid | string | 认证器的认证GUID,指示认证器的类型 |
配置选项
rpID:您网站的唯一标识符。对于本地开发环境,'localhost' 是可以接受的。
rpName:您网站的可读性标题。
origin:注册和认证应发生的URL。http://localhost
和 http://localhost:端口号
也是有效的。请勿包含任何结尾的 /
。
authenticatorSelector:允许自定义 WebAuthn 认证器的选择标准。未指定时,平台认证器和跨平台认证器均被允许,且 residentKey
和 userVerification
采用 preferred
设置。
aaguid:(可选)认证器证明 GUID。这是通行密钥提供者(设备或认证器类型)的唯一标识符,可用于识别注册或认证过程中使用的通行密钥设备类型。