手机号码

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

安装

将插件添加到服务器

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

迁移数据库

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

npx @better-auth/cli migrate

查看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端点。

auth-client.ts
await authClient.phoneNumber.sendOtp({
    phoneNumber: "+1234567890"
})

验证手机号码

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

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

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

允许使用手机号码注册

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

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

使用手机号码登录

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

await authClient.signIn.phoneNumber({
    phoneNumber: "+123456789",
    password: "password",
    rememberMe: true //可选,默认为true
})

更新手机号码

更新手机号码使用与验证手机号码相同的流程。用户将收到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启动忘记密码流程,您可以先调用客户端上的forgetPassword向用户的手机号码发送OTP验证码。

auth-client.ts
await authClient.phoneNumber.forgetPassword({
    phoneNumber: "+1234567890"
})

然后,您可以通过使用OTP验证码和新密码调用客户端上的resetPassword来重设密码。

auth-client.ts
const isVerified = await authClient.phoneNumber.resetPassword({
    otp: "123456", // 发送到用户手机号码的OTP验证码
    phoneNumber: "+1234567890",
    newPassword: "newPassword"
})  

选项

  • 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) => {
                // 实现手机号码验证后的回调
            }
        })
    ]
})
  • phoneNumberValidator: 验证手机号码的自定义函数。它接受手机号码作为参数,并返回一个布尔值,指示手机号码是否有效。

  • signUpOnVerification: 具有以下属性的对象:

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

Schema

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

用户表

Field NameTypeKeyDescription
phoneNumberstring用户的手机号码
phoneNumberVerifiedboolean手机号码是否已验证

OTP验证尝试

手机号码插件包含内置保护,防止暴力攻击,方法是限制每个OTP验证码的验证尝试次数。

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

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

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

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

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

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

On this page