电话号码

电话号码插件通过允许用户使用电话号码登录和注册来扩展认证系统。它包含 OTP(一次性密码)功能来验证电话号码。

安装

将插件添加到服务器

auth.ts
import { betterAuth } from "better-auth"
import { phoneNumber } from "better-auth/plugins"

const auth = betterAuth({
    plugins: [ 
        phoneNumber({  
            sendOTP: ({ phoneNumber, code }, request) => { 
                // Implement sending OTP code via SMS
            } 
        }) 
    ] 
})

迁移数据库

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

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

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

添加客户端插件

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

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

使用

发送 OTP 以进行验证

要向用户电话号码发送 OTP 以进行验证,您可以使用 sendVerificationCode 端点。

POST
/phone-number/send-otp
const { data, error } = await authClient.phoneNumber.sendOtp({    phoneNumber: "+1234567890", // required});
PropDescriptionType
phoneNumber
要发送 OTP 的电话号码。
string

验证电话号码

OTP 发送后,用户可以通过提供代码来验证他们的电话号码。

POST
/phone-number/verify
const { data, error } = await authClient.phoneNumber.verify({    phoneNumber: "+1234567890", // required    code: "123456", // required    disableSession: false,    updatePhoneNumber: true,});
PropDescriptionType
phoneNumber
要验证的电话号码。
string
code
OTP 代码。
string
disableSession?
验证后禁用会话创建。
boolean
updatePhoneNumber?
检查是否存在会话并更新电话号码。
boolean

电话号码验证后,用户表中的 phoneNumberVerified 字段将被设置为 true。如果未将 disableSession 设置为 true,则将为用户创建一个会话。此外,如果提供了 callbackOnVerification,它将被调用。

允许使用电话号码注册

要允许用户使用电话号码注册,您可以将 signUpOnVerification 选项传递给插件配置。它要求您传递 getTempEmail 函数来为用户生成临时电子邮件。

auth.ts
export const auth = betterAuth({
    plugins: [
        phoneNumber({
            sendOTP: ({ phoneNumber, code }, request) => {
                // Implement sending OTP code via SMS
            },
            signUpOnVerification: {
                getTempEmail: (phoneNumber) => {
                    return `${phoneNumber}@my-site.com`
                },
                //optionally, you can also pass `getTempName` function to generate a temporary name for the user
                getTempName: (phoneNumber) => {
                    return phoneNumber //by default, it will use the phone number as the name
                }
            }
        })
    ]
})

使用电话号码登录

除了使用发送-验证流程登录用户外,您还可以将电话号码用作标识符,并使用电话号码和密码登录用户。

POST
/sign-in/phone-number
const { data, error } = await authClient.signIn.phoneNumber({    phoneNumber: "+1234567890", // required    password, // required    rememberMe: true,});
PropDescriptionType
phoneNumber
要登录的电话号码。
string
password
用于登录的密码。
string
rememberMe?
记住会话。
boolean

更新电话号码

更新电话号码使用与验证电话号码相同的流程。用户将收到 OTP 代码来验证新电话号码。

auth-client.ts
await authClient.phoneNumber.sendOtp({
    phoneNumber: "+1234567890" // 新电话号码
})

然后使用 OTP 代码验证新电话号码。

auth-client.ts
const isVerified = await authClient.phoneNumber.verify({
    phoneNumber: "+1234567890",
    code: "123456",
    updatePhoneNumber: true // 设置为 true 以更新电话号码
})

如果用户会话存在,电话号码将自动更新。

禁用会话创建

默认情况下,插件在验证电话号码后为用户创建会话。您可以通过向 verify 方法传递 disableSession: true 来禁用此行为。

auth-client.ts
const isVerified = await authClient.phoneNumber.verify({
    phoneNumber: "+1234567890",
    code: "123456",
    disableSession: true
})

请求密码重置

要使用 phoneNumber 启动请求密码重置流程,您可以首先在客户端调用 requestPasswordReset 以向用户电话号码发送 OTP 代码。

POST
/phone-number/request-password-reset
const { data, error } = await authClient.phoneNumber.requestPasswordReset({    phoneNumber: "+1234567890", // required});
PropDescriptionType
phoneNumber
与用户关联的电话号码。
string

然后,您可以通过在客户端调用 resetPassword 并使用 OTP 代码和新密码来重置密码。

POST
/phone-number/reset-password
const { data, error } = await authClient.phoneNumber.resetPassword({    otp: "123456", // required    phoneNumber: "+1234567890", // required    newPassword: "new-and-secure-password", // required});
PropDescriptionType
otp
重置密码的一次性密码。
string
phoneNumber
打算为其重置密码的账户的电话号码。
string
newPassword
新密码。
string

选项

  • otpLength: 要生成的 OTP 代码长度。默认为 6
  • sendOTP: 一个函数,用于向用户电话号码发送 OTP 代码。它将电话号码和 OTP 代码作为参数。
  • expiresIn: OTP 代码过期后的秒数。默认为 300 秒。
  • callbackOnVerification: 在电话号码验证后调用的函数。它将电话号码和用户对象作为第一个参数,并将请求对象作为第二个参数。
export const auth = betterAuth({
    plugins: [
        phoneNumber({
            sendOTP: ({ phoneNumber, code }, request) => {
                // Implement sending OTP code via SMS
            },
            callbackOnVerification: async ({ phoneNumber, user }, request) => {
                // Implement callback after phone number verification
            }
        })
    ]
})
  • sendPasswordResetOTP: 一个函数,用于向用户电话号码发送 OTP 代码以进行密码重置。它将电话号码和 OTP 代码作为参数。

  • phoneNumberValidator: 一个自定义函数,用于验证电话号码。它将电话号码作为参数,并返回一个布尔值,表示电话号码是否有效。

  • signUpOnVerification: 一个包含以下属性的对象:

    • getTempEmail: 一个函数,用于为用户生成临时电子邮件。它将电话号码作为参数并返回临时电子邮件。
    • getTempName: 一个函数,用于为用户生成临时名称。它将电话号码作为参数并返回临时名称。
  • requireVerification: 启用后,用户在电话号码验证之前无法使用电话号码登录。如果未验证的用户尝试登录,服务器将响应 401 错误(PHONE_NUMBER_NOT_VERIFIED)并自动触发 OTP 发送以启动验证过程。

架构

该插件要求向用户表添加 2 个字段

用户表

Field NameTypeKeyDescription
phoneNumberstring用户的电话号码
phoneNumberVerifiedboolean电话号码是否已验证

OTP 验证尝试

电话号码插件通过限制每个 OTP 代码的验证尝试次数来内置保护免受暴力攻击。

phoneNumber({
  allowedAttempts: 3, // 默认值为 3
  // ... other options
})

当用户超过允许的验证尝试次数时:

  • OTP 代码将被自动删除
  • 进一步的验证尝试将返回 403(禁止)状态,并带有“尝试次数过多”消息
  • 用户需要请求新的 OTP 代码才能继续

超过尝试次数后的示例错误响应:

{
  "error": {
    "status": 403,
    "message": "Too many attempts"
  }
}

接收到 403 状态时,提示用户请求新的 OTP 代码

On this page