双重身份验证 (2FA)
通过双重身份验证增强您的应用安全性。
OTP TOTP 备用代码 受信设备
双重身份验证 (2FA) 在用户登录时增加了一道额外的安全步骤。用户不仅需要密码,还需提供第二种验证方式。这使得即使密码泄露,未经授权的人也更难访问账户。
此插件提供两种主要的二次验证方法:
- OTP (一次性密码):发送到用户邮箱或手机的临时代码。
- TOTP (基于时间的一次性密码):由用户设备上的应用生成的代码。
附加功能包括:
- 生成备用代码用于账户恢复
- 启用/禁用 2FA
- 管理受信设备
安装
将插件添加到您的身份验证配置中
将双重身份验证插件添加到您的身份验证配置,并将您的应用名称指定为发布者。
import { betterAuth } from "better-auth"
import { twoFactor } from "better-auth/plugins"
export const auth = betterAuth({
// ... 其他配置选项
appName: "My App", // 提供您的应用名称。它将作为发布者使用。
plugins: [
twoFactor()
]
})添加客户端插件
添加客户端插件,并指定用户需要进行二次验证时的重定向地址。
import { createAuthClient } from "better-auth/client"
import { twoFactorClient } from "better-auth/client/plugins"
export const authClient = createAuthClient({
plugins: [
twoFactorClient()
]
})使用
启用 2FA
要启用双重身份验证,调用 twoFactor.enable,传入用户密码和可选的发布者:
const { data, error } = await authClient.twoFactor.enable({ password: "secure-password", // required issuer: "my-app-name",});passwordstringrequired用户密码
issuerstring可选的 TOTP URI 发布者。默认是身份验证配置中的 app-name。
启用 2FA 时:
- 会生成加密的
secret和backupCodes。 enable返回totpURI和backupCodes。
注意:在用户验证他们的 TOTP 代码之前,twoFactorEnabled 不会被设置为 true。了解更多关于 TOTP 验证内容请参阅这里。您也可以在插件配置中将 skipVerificationOnEnable 设置为 true,跳过验证。
当前双重身份验证只支持凭证账户(credential accounts)。对于社交账户,默认假设提供商已处理 2FA。
使用 2FA 登录
当启用了 2FA 的用户通过邮箱登录时,响应对象中会包含 twoFactorRedirect 并设置为 true,表示用户需要验证他们的 2FA 代码。
您可以在 onSuccess 回调中处理,或在插件配置中提供 onTwoFactorRedirect 回调。
import { authClient } from "@/lib/auth-client"
await authClient.signIn.email({
email: "user@example.com",
password: "password123",
},
{
async onSuccess(context) {
if (context.data.twoFactorRedirect) {
// 处理当前页面上的 2FA 验证
}
},
}
)使用 onTwoFactorRedirect 配置示例:
import { createAuthClient } from "better-auth/client";
import { twoFactorClient } from "better-auth/client/plugins";
const authClient = createAuthClient({
plugins: [
twoFactorClient({
onTwoFactorRedirect(){
// 全局处理 2FA 验证
},
}),
],
});关于 auth.api
当您在服务器调用 auth.api.signInEmail 并且用户启用了 2FA 时,返回的对象中会含有 twoFactorRedirect 并设置为 true。这种行为在 TypeScript 中不会被类型推断,可能会导致误导。您可以使用 in 操作符检查是否含有 twoFactorRedirect。
import { auth } from "@/lib/auth"
const response = await auth.api.signInEmail({
body: {
email: "test@test.com",
password: "test",
},
});
if ("twoFactorRedirect" in response) {
// 处理当前页面上的 2FA 验证
}禁用 2FA
要禁用双重身份验证,调用 twoFactor.disable 并传入用户密码:
const { data, error } = await authClient.twoFactor.disable({ password, // required});passwordstringrequired用户密码
TOTP
TOTP(基于时间的一次性密码)是一种使用时间计数器为每次登录生成唯一密码的算法。每隔固定时间(Better Auth 默认 30 秒)生成一个新密码。它解决了传统密码可能被遗忘、窃取或猜测的问题。虽然 OTP 也解决了一部分问题,但通过短信或邮箱发送 OTP 的可靠性较差(甚至较风险,因为可能带来新的攻击面)。
而 TOTP 是线下生成代码,既安全又便捷。只需在手机安装认证器应用即可。
获取 TOTP URI
启用 2FA 后,可获取 TOTP URI 并向用户展示。该 URI 是服务器基于 secret 与 issuer 生成,用于生成二维码,供用户用认证器扫描。
const { data, error } = await authClient.twoFactor.getTotpUri({ password, // required});passwordstringrequired用户密码
示例:React 方式
获取 TOTP URI 后,您可用它生成二维码,供用户用认证器扫描。
import { authClient } from "@/lib/auth-client"
import QRCode from "react-qr-code";
export default function UserCard({ password }: { password: string }){
const { data: session } = authClient.useSession();
const { data: qr } = useQuery({
queryKey: ["two-factor-qr"],
queryFn: async () => {
const res = await authClient.twoFactor.getTotpUri({ password });
return res.data;
},
enabled: !!session?.user.twoFactorEnabled,
});
return (
<QRCode value={qr?.totpURI || ""} />
)
}默认情况下,TOTP 的发布者为身份验证配置中的应用名称,如果未指定,则默认为 Better Auth。您可以通过传入 issuer 至插件配置来覆盖默认值。
验证 TOTP
用户输入 2FA 代码后,可调用 twoFactor.verifyTotp 方法进行验证。Better Auth 遵循标准做法,接受当前时间段前后各一个周期内的代码,确保用户即使存在轻微时间偏差也可认证成功。
const { data, error } = await authClient.twoFactor.verifyTotp({ code: "012345", // required trustDevice: true,});codestringrequired待验证的 otp 代码。
trustDeviceboolean若为 true,该设备将在 30 天内被信任。期间每次登录均刷新信任期限。
OTP
OTP(一次性密码)与 TOTP 类似,但生成的随机码会通过邮件或短信发给用户。
在使用 OTP 进行二次验证前,您需要在 Better Auth 实例中配置 sendOTP。该函数负责将 OTP 发送给用户的邮箱、手机或其他支持的方式。
import { betterAuth } from "better-auth"
import { twoFactor } from "better-auth/plugins"
export const auth = betterAuth({
plugins: [
twoFactor({
otpOptions: {
async sendOTP({ user, otp }, ctx) {
// 发送 otp 给用户
},
},
})
]
})发送 OTP
发送 OTP 通过调用 twoFactor.sendOtp 完成。该函数会触发您在 Better Auth 配置中提供的 sendOTP 实现。
const { data, error } = await authClient.twoFactor.sendOtp({ trustDevice: true,});if (data) { // 重定向或提示用户输入代码}trustDeviceboolean若为 true,该设备将在 30 天内被信任。期间每次登录均刷新信任期限。
验证 OTP
用户输入 OTP 代码后,您可进行验证。
const { data, error } = await authClient.twoFactor.verifyOtp({ code: "012345", // required trustDevice: true,});codestringrequired待验证 otp 代码。
trustDeviceboolean若为 true,该设备将在 30 天内被信任。期间每次登录均刷新信任期限。
备用代码
备用代码存储于数据库。当用户失去手机或邮箱访问权限时,可用于账户恢复。
生成备用代码
生成用于账户恢复的备用代码:
const { data, error } = await authClient.twoFactor.generateBackupCodes({ password, // required});if (data) { // 显示备用代码给用户}passwordstringrequired用户密码。
生成备用代码时,旧的备用代码会被删除,生成新的。
使用备用代码
您可允许用户使用备用代码作为账户恢复方式。
const { data, error } = await authClient.twoFactor.verifyBackupCode({ code: "123456", // required disableSession: false, trustDevice: true,});codestringrequired待验证的备用代码。
disableSessionboolean若为 true,不会设置会话 cookie。
trustDeviceboolean若为 true,该设备将在 30 天内被信任。期间每次登录均刷新信任期限。
一旦备用代码被使用,它会从数据库中移除,且不可再次使用。
查看备用代码
要向用户展示备用代码,可在服务器调用 viewBackupCodes,返回备用代码。请确保仅允许拥有刚创建的新鲜会话的用户执行此操作。
const data = await auth.api.viewBackupCodes({ body: { userId: "user-id", },});userIdstring | null要查看备用代码的用户 ID。
受信设备
您可以通过向 verifyTotp 或 verifyOtp 传入 trustDevice 来标记设备为受信设备。
const verify2FA = async (code: string) => {
const { data, error } = await authClient.twoFactor.verifyTotp({
code,
trustDevice: true, // 标记当前设备为受信设备
})
if (data) {
// 2FA 验证成功且设备被标记受信
}
}当 trustDevice 设置为 true,当前设备将在 30 天内被记为受信设备。在此期间,用户通过该设备再次登录时不会被提示进行 2FA 验证。每次成功登录都会刷新该受信期限。
发布者(Issuer)
通过添加 issuer,您可以设置应用名称,该名称会显示在 2FA 应用中。
例如,若用户使用 Google Auth,默认 appName 会显示为 Better Auth。您可如下配置,使其显示为 my-app-name。
twoFactor({
issuer: "my-app-name"
})模式 (Schema)
该插件需要在 user 表中添加 1 个额外字段,且新增 1 个表用于存储双重身份验证数据。
表:user
表:twoFactor
配置选项
服务器端
twoFactorTable:存储双重身份验证数据的表名。默认值:twoFactor。
skipVerificationOnEnable:启用用户的双重身份验证时,跳过验证过程。
Issuer:应用的名称,用于生成 TOTP 代码,会显示在认证器应用中。
TOTP 选项
TOTP 的相关配置。
Prop
Type
OTP 选项
OTP 的相关配置。
Prop
Type
备用代码选项
当用户启用双重身份验证时,备用代码会被生成并存储,用于在用户无法访问手机或邮箱时恢复账户。
Prop
Type
客户端
在客户端使用双重身份验证插件时,需要将其添加到插件列表中。
import { createAuthClient } from "better-auth/client"
import { twoFactorClient } from "better-auth/client/plugins"
const authClient = createAuthClient({
plugins: [
twoFactorClient({
onTwoFactorRedirect(){
window.location.href = "/2fa" // 处理 2FA 验证重定向
}
})
]
})选项
onTwoFactorRedirect:当用户需要验证 2FA 代码时调用的回调函数。您可以用它来重定向用户到 2FA 页面。