电话号码

手机号插件扩展了认证系统,允许用户使用手机号进行登录和注册。它包含 OTP(一次性密码)功能来验证手机号。

安装

在服务端添加插件

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

const auth = betterAuth({
    plugins: [
        phoneNumber({  
            sendOTP: ({ phoneNumber, code }, request) => { 
                // 实现通过短信发送 OTP 验证码
            } 
        }) 
    ]
})

迁移数据库

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

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() 
    ] 
})

使用方法

发送验证码进行验证

要向用户的手机号发送验证码进行验证,可以使用 sendVerificationCode 端点。

POST
/phone-number/send-otp
const { data, error } = await authClient.phoneNumber.sendOtp({    phoneNumber: "+1234567890", // required});
属性描述类型
phoneNumber
要发送验证码的手机号
string

验证手机号

验证码发送后,用户可以通过提供验证码来验证其手机号。

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

当手机号验证成功后,用户表中的 phoneNumberVerified 字段将被设置为 true。如果 disableSession 未设置为 true,系统将为用户创建一个会话。此外,如果提供了 callbackOnVerification,该回调将被调用。

允许使用手机号注册

要允许用户使用手机号注册,您可以在插件配置中传递 signUpOnVerification 选项。这需要您传递 getTempEmail 函数来为用户生成临时邮箱。

auth.ts
export const auth = betterAuth({
    plugins: [
        phoneNumber({
            sendOTP: ({ phoneNumber, code }, request) => {
                // 实现通过短信发送验证码
            },
            signUpOnVerification: {
                getTempEmail: (phoneNumber) => {
                    return `${phoneNumber}@my-site.com`
                },
                // 可选,您也可以传递 `getTempName` 函数来为用户生成临时名称
                getTempName: (phoneNumber) => {
                    return phoneNumber // 默认情况下,将使用手机号作为名称
                }
            }
        })
    ]
})

使用手机号登录

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

POST
/sign-in/phone-number
const { data, error } = await authClient.signIn.phoneNumber({    phoneNumber: "+1234567890", // required    password, // required    rememberMe: true,});
属性描述类型
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});
属性描述类型
phoneNumber
与该用户关联的手机号码。
string

然后,您可以在客户端使用 OTP 验证码和新密码调用 resetPassword 来重置密码。

POST
/phone-number/reset-password
const { data, error } = await authClient.phoneNumber.resetPassword({    otp: "123456", // required    phoneNumber: "+1234567890", // required    newPassword: "new-and-secure-password", // required});
属性描述类型
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) => {
                // 实现通过短信发送 OTP 验证码的逻辑
            },
            callbackOnVerification: async ({ phoneNumber, user }, request) => {
                // 实现手机号验证成功后的回调逻辑
            }
        })
    ]
})
  • sendPasswordResetOTP: 用于密码重置时向用户手机号发送 OTP 验证码的函数。接收手机号和 OTP 验证码作为参数。

  • phoneNumberValidator: 自定义的手机号验证函数。接收手机号作为参数,返回布尔值表示手机号是否有效。

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

    • getTempEmail: 为用户生成临时邮箱的函数。接收手机号作为参数,返回临时邮箱地址。
    • getTempName: 为用户生成临时名称的函数。接收手机号作为参数,返回临时名称。
  • requireVerification: 启用后,用户必须验证手机号才能使用手机号登录。如果未验证的用户尝试登录,服务器将返回 401 错误(PHONE_NUMBER_NOT_VERIFIED)并自动触发发送 OTP 验证码以启动验证流程。

数据库结构

该插件需要在用户表中添加 2 个字段

用户表

字段名称类型Key描述
phoneNumberstring用户的电话号码
phoneNumberVerifiedboolean电话号码是否已验证

OTP 验证尝试

电话号码插件内置了防止暴力破解攻击的保护机制,通过限制每个 OTP 代码的验证尝试次数来实现。

phoneNumber({
  allowedAttempts: 3, // 默认为 3
  // ... 其他选项
})

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

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

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

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

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

On this page