电话号码
电话号码插件
电话号码插件通过允许用户使用电话号码登录和注册,扩展了认证系统。它包含用于验证电话号码的一次性密码(OTP)功能。
安装
将插件添加到服务器
import { betterAuth } from "better-auth"
import { phoneNumber } from "better-auth/plugins"
const auth = betterAuth({
plugins: [
phoneNumber({
sendOTP: ({ phoneNumber, code }, ctx) => {
// 实现通过短信发送 OTP 代码
}
})
]
})添加客户端插件
import { createAuthClient } from "better-auth/client"
import { phoneNumberClient } from "better-auth/client/plugins"
const authClient = createAuthClient({
plugins: [
phoneNumberClient()
]
})使用
发送 OTP 以进行验证
要向用户的电话号码发送 OTP 以进行验证,可以使用 sendVerificationCode 接口。
const { data, error } = await authClient.phoneNumber.sendOtp({ phoneNumber: "+1234567890", // required});phoneNumberstringrequired用于发送 OTP 的电话号码。
验证电话号码
发送 OTP 后,用户可以通过提供验证码来验证其电话号码。
const { data, error } = await authClient.phoneNumber.verify({ phoneNumber: "+1234567890", // required code: "123456", // required disableSession: false, updatePhoneNumber: false,});phoneNumberstringrequired需验证的电话号码。
codestringrequiredOTP 代码。
disableSessionboolean验证后禁用会话创建。
updatePhoneNumberboolean更新已登录用户的电话号码。 需要有效的会话。
允许使用电话号码注册
要允许用户使用电话号码注册,可以将 signUpOnVerification 选项传递给插件配置。需要传递 getTempEmail 函数为用户生成临时邮箱。
import { betterAuth } from "better-auth";
import { phoneNumber } from "better-auth/plugins"
export const auth = betterAuth({
plugins: [
phoneNumber({
sendOTP: ({ phoneNumber, code }, ctx) => {
// 实现通过短信发送 OTP 代码
},
signUpOnVerification: {
getTempEmail: (phoneNumber) => {
return `${phoneNumber}@my-site.com`
},
// 可选,您也可以传递 `getTempName` 函数为用户生成临时名称
getTempName: (phoneNumber) => {
return phoneNumber // 默认使用电话号码作为名称
}
}
})
]
})强烈建议不要等待 sendOTP 函数完成。如果等待,将会延迟请求并可能导致时序攻击。对于无服务器平台,可以使用 waitUntil 确保 OTP 被发送。
如果您的用户架构中有额外的必填字段,可以在验证请求体中传递它们:
await authClient.phoneNumber.verify({
phoneNumber: "+1234567890",
code: "123456",
customField: "custom-value", // 额外字段
})使用电话号码登录
除了通过发送-验证流程登录用户,您还可以使用电话号码作为标识符,通过电话号码和密码登录用户。
const { data, error } = await authClient.signIn.phoneNumber({ phoneNumber: "+1234567890", // required password, // required rememberMe: true,});phoneNumberstringrequired用于登录的电话号码。
passwordstringrequired用于登录的密码。
rememberMeboolean记住会话。
更新电话号码
已经登录的用户可以将其电话号码更改为新的号码。首先,向新的电话号码发送 OTP:
import { authClient } from "@/lib/auth-client";
await authClient.phoneNumber.sendOtp({
phoneNumber: "+1234567890" // 新的电话号码
})然后使用 updatePhoneNumber: true 验证新的电话号码:
import { authClient } from "@/lib/auth-client";
const isVerified = await authClient.phoneNumber.verify({
phoneNumber: "+1234567890",
code: "123456",
updatePhoneNumber: true
})禁用会话创建
默认情况下,插件在验证电话号码后会为用户创建会话。您可以通过向 verify 方法传递 disableSession: true 来禁用此行为。
import { authClient } from "@/lib/auth-client";
const isVerified = await authClient.phoneNumber.verify({
phoneNumber: "+1234567890",
code: "123456",
disableSession: true
})请求密码重置
要使用 phoneNumber 启动密码重置请求流程,可以先调用客户端的 requestPasswordReset 接口向用户的电话号码发送 OTP 代码。
const { data, error } = await authClient.phoneNumber.requestPasswordReset({ phoneNumber: "+1234567890", // required});phoneNumberstringrequired与用户关联的电话号码。
然后,您可以通过客户端调用 resetPassword 接口,使用 OTP 代码和新密码重置密码。
const { data, error } = await authClient.phoneNumber.resetPassword({ otp: "123456", // required phoneNumber: "+1234567890", // required newPassword: "new-and-secure-password", // required});otpstringrequired用于重置密码的一次性密码。
phoneNumberstringrequired需重置密码的账户电话号码。
newPasswordstringrequired新密码。
选项
otpLength
生成 OTP 代码的长度。默认是 6。
sendOTP
一个发送 OTP 代码到用户电话号码的函数。接收电话号码和 OTP 代码作为参数。
expiresIn
OTP 代码过期的时间,单位为秒。默认是 300 秒。
callbackOnVerification
电话号码验证后调用的函数。第一个参数包含电话号码和用户对象,第二个参数是请求对象。
import { betterAuth } from "better-auth";
import { phoneNumber } from "better-auth/plugins"
export const auth = betterAuth({
plugins: [
phoneNumber({
sendOTP: ({ phoneNumber, code }, ctx) => {
// 实现通过短信发送 OTP 代码
},
callbackOnVerification: async ({ phoneNumber, user }, ctx) => {
// 实现电话号码验证后的回调
}
})
]
})sendPasswordResetOTP
发送 OTP 代码到用户电话号码用于密码重置的函数。接收电话号码和 OTP 代码作为参数。
phoneNumberValidator
自定义电话号码验证函数。接收电话号码为参数,返回布尔值表示电话号码是否有效。
verifyOTP
自定义 OTP 验证函数。提供后将替代默认内部验证逻辑。适用于需集成外部短信服务提供商(如 Twilio Verify、AWS SNS)进行 OTP 验证的场景。函数接收带有 phoneNumber 和 code 属性的对象及请求对象,返回布尔值或返回布尔值的 Promise,表示 OTP 是否有效。
import { betterAuth } from "better-auth";
import { phoneNumber } from "better-auth/plugins"
export const auth = betterAuth({
plugins: [
phoneNumber({
sendOTP: ({ phoneNumber, code }, ctx) => {
// 通过您的短信服务提供商发送 OTP
},
verifyOTP: async ({ phoneNumber, code }, ctx) => {
// 使用您选择的方式验证 OTP(例如 Twilio Verify)
// 以下为示例,非真实实现。
const isValid = await twilioClient.verify
.services('YOUR_SERVICE_SID')
.verificationChecks
.create({ to: phoneNumber, code });
return isValid.status === 'approved';
}
})
]
})使用此选项时,请确保实现了适当的验证,因为这将覆盖内部验证逻辑。
signUpOnVerification
一个包含以下属性的对象:
getTempEmail: 用于为用户生成临时邮箱的函数,接收电话号码为参数,返回临时邮箱字符串。getTempName: 用于为用户生成临时名称的函数,接收电话号码为参数,返回临时名称字符串。
requireVerification
启用后,用户在验证电话号码前无法使用该电话号码登录。如果未验证用户尝试登录,服务器将返回 401 错误(PHONE_NUMBER_NOT_VERIFIED),并自动触发 OTP 发送,启动验证流程。
架构
本插件需要向用户表中添加2个字段
用户表
OTP 验证尝试次数限制
电话号码插件内置防暴力攻击保护,限制每个 OTP 代码的验证尝试次数。
phoneNumber({
allowedAttempts: 3, // 默认是3
// ... 其它选项
})当用户超过允许的验证尝试次数时:
- OTP 代码会自动删除
- 进一步的验证尝试会返回 403(禁止访问)状态及“尝试次数过多”提示
- 用户需重新请求新的 OTP 代码以继续操作
超出尝试次数后的示例错误响应:
{
"error": {
"status": 403,
"message": "尝试次数过多"
}
}接收到 403 状态码时,请提示用户请求新的 OTP 代码