邮箱与密码认证

电子邮件和密码认证是许多应用程序常用的认证方式。Better Auth 提供了一个内置的电子邮件和密码认证器,您可以轻松地将其集成到您的项目中。

如果您更喜欢基于用户名的认证,请查看 用户名插件。它扩展了 电子邮件和密码认证器,提供了用户名支持。

启用电子邮件和密码认证

要启用电子邮件和密码认证,您需要在 auth 配置中将 emailAndPassword.enabled 选项设置为 true

auth.ts
import { betterAuth } from "better-auth";

export const auth = betterAuth({
  emailAndPassword: { 
    enabled: true, 
  }, 
});

如果未启用此选项,将不允许您使用电子邮件和密码进行注册或登录。

使用方法

注册

要注册用户,您可以使用客户端提供的 signUp.email 函数。

POST
/sign-up/email
const { data, error } = await authClient.signUp.email({    name: "John Doe", // required    email: "john.doe@example.com", // required    password: "password1234", // required    image: "https://example.com/image.png",    callbackURL: "https://example.com/callback",});
属性描述类型
name
用户名
string
email
用户的电子邮件地址
string
password
用户密码。默认情况下,密码长度应至少为8个字符,最多128个字符。
string
image?
可选的用户个人资料图片
string
callbackURL?
用户注册后重定向的可选URL
string

这些是注册电子邮件端点的默认属性,但通过附加字段或特殊插件,您可以向端点传递更多属性。

用户登录

要使用户登录,您可以使用客户端提供的 signIn.email 函数。

POST
/sign-in/email
const { data, error } = await authClient.signIn.email({    email: "john.doe@example.com", // required    password: "password1234", // required    rememberMe: true,    callbackURL: "https://example.com/callback",});
属性描述类型
email
用户的邮箱地址。
string
password
用户的密码。默认情况下,密码长度应至少为8个字符,最多128个字符。
string
rememberMe?
如果为 false,用户将在浏览器关闭时自动退出登录。(可选)(默认值:true)
boolean
callbackURL?
用户登录后重定向的可选 URL。(可选)
string

这些是登录邮箱端点的默认属性,但通过附加字段或特殊插件,您也可以向该端点传递不同的属性。

用户退出登录

要使用户退出登录,您可以使用客户端提供的 signOut 函数。

POST
/sign-out
await authClient.signOut();

您可以通过传递 fetchOptions 在成功时进行重定向

auth-client.ts
await authClient.signOut({
  fetchOptions: {
    onSuccess: () => {
      router.push("/login"); // 重定向到登录页面
    },
  },
});

邮箱验证

要启用邮箱验证功能,您需要传递一个发送验证邮件(包含验证链接)的函数。sendVerificationEmail 函数接收一个包含以下属性的数据对象作为第一个参数:

  • user:用户对象
  • url:发送给用户的包含令牌的 URL
  • token:用于完成邮箱验证的验证令牌

以及一个 request 对象作为第二个参数。

auth.ts
import { betterAuth } from "better-auth";
import { sendEmail } from "./email"; // 您的邮件发送函数

export const auth = betterAuth({
  emailVerification: {
    sendVerificationEmail: async ( { user, url, token }, request) => {
      await sendEmail({
        to: user.email,
        subject: "验证您的邮箱地址",
        text: `请点击链接验证您的邮箱:${url}`,
      });
    },
  },
});

在客户端,您可以使用 sendVerificationEmail 函数向用户发送验证链接。这将触发您在 auth 配置中提供的 sendVerificationEmail 函数。

当用户点击邮件中的链接后,如果令牌有效,用户将被重定向到 callbackURL 参数中提供的 URL。如果令牌无效,用户将被重定向到 callbackURL 参数中提供的 URL,并在查询字符串中包含错误信息 ?error=invalid_token

要求邮箱验证

如果启用要求邮箱验证功能,用户必须先验证邮箱才能登录。每次用户尝试登录时,系统都会调用 sendVerificationEmail 函数。

此功能仅在您已实现 sendVerificationEmail 且用户尝试使用邮箱和密码登录时生效。

auth.ts
export const auth = betterAuth({
  emailAndPassword: {
    requireEmailVerification: true,
  },
});

如果用户尝试在未验证邮箱的情况下登录,您可以处理错误并向用户显示提示信息。

auth-client.ts
await authClient.signIn.email(
  {
    email: "email@example.com",
    password: "password",
  },
  {
    onError: (ctx) => {
      // 处理错误
      if (ctx.error.status === 403) {
        alert("请验证您的邮箱地址");
      }
      // 也可以显示原始错误信息
      alert(ctx.error.message);
    },
  }
);

手动触发邮箱验证

您可以通过调用 sendVerificationEmail 函数手动触发邮箱验证。

await authClient.sendVerificationEmail({
  email: "user@email.com",
  callbackURL: "/", // 验证完成后的重定向 URL
});

请求密码重置

要允许用户重置密码,首先需要为邮箱和密码认证器提供 sendResetPassword 函数。sendResetPassword 函数接收一个包含以下属性的数据对象:

  • user: 用户对象
  • url: 发送给用户的包含令牌的 URL
  • token: 用于完成密码重置的验证令牌

以及一个作为第二个参数的 request 对象。

auth.ts
import { betterAuth } from "better-auth";
import { sendEmail } from "./email"; // 你的邮件发送函数

export const auth = betterAuth({
  emailAndPassword: {
    enabled: true,
    sendResetPassword: async ({user, url, token}, request) => {
      await sendEmail({
        to: user.email,
        subject: "重置您的密码",
        text: `点击链接重置密码:${url}`,
      });
    },
    onPasswordReset: async ({ user }, request) => {
      // 在此处添加你的逻辑
      console.log(`用户 ${user.email} 的密码已重置。`);
    },
  },
});

此外,你还可以提供一个 onPasswordReset 回调函数,在密码成功重置后执行逻辑。

配置好服务器后,你可以调用 requestPasswordReset 函数向用户发送密码重置链接。如果用户存在,它将触发你在认证配置中提供的 sendResetPassword 函数。

POST
/request-password-reset
const { data, error } = await authClient.requestPasswordReset({    email: "john.doe@example.com", // required    redirectTo: "https://example.com/reset-password",});
属性描述类型
email
要发送密码重置邮件的用户邮箱地址
string
redirectTo?
重定向用户重置密码的 URL。如果令牌无效或过期,将通过查询参数 ?error=INVALID_TOKEN 重定向。如果令牌有效,将通过查询参数 ?token=VALID_TOKEN 重定向
string

当用户点击邮件中的链接时,他们将被重定向到密码重置页面。你可以在应用中添加密码重置页面,然后使用 resetPassword 函数来重置密码。该函数接收一个包含以下属性的对象:

  • newPassword: 用户的新密码
auth-client.ts
const { data, error } = await authClient.resetPassword({
  newPassword: "password1234",
  token,
});
POST
/reset-password
const token = new URLSearchParams(window.location.search).get("token");if (!token) {  // 处理错误}const { data, error } = await authClient.resetPassword({    newPassword: "password1234", // required    token, // required});
属性描述类型
newPassword
要设置的新密码
string
token
用于重置密码的令牌
string

更新密码

用户的密码不会存储在用户表中,而是存储在账户表中。要更改用户的密码,您可以使用以下方法之一:

POST
/change-password
const { data, error } = await authClient.changePassword({    newPassword: "newpassword1234", // required    currentPassword: "oldpassword1234", // required    revokeOtherSessions: true,});
属性描述类型
newPassword
要设置的新密码
string
currentPassword
当前用户密码
string
revokeOtherSessions?
设置为 true 时,此用户的所有其他活动会话将被失效
boolean

配置

密码

Better Auth 将密码存储在 account 表中,其中 providerId 设置为 credential

密码哈希:Better Auth 使用 scrypt 算法进行密码哈希处理。scrypt 算法设计为计算缓慢且内存密集型,这使得攻击者难以进行密码暴力破解。OWASP 建议在无法使用 argon2id 的情况下使用 scrypt。我们选择使用 scrypt 是因为它被 Node.js 原生支持。

您可以通过在 auth 配置中设置 passwordHasher 选项来自定义密码哈希算法。

auth.ts
import { betterAuth } from "better-auth"
import { scrypt } from "scrypt"

export const auth = betterAuth({
    //...其余选项
    emailAndPassword: {
        password: {
            hash: // 您的自定义密码哈希函数
            verify: // 您的自定义密码验证函数
        }
    }
})
PropTypeDefault
enabled?
boolean
false
disableSignUp?
boolean
false
minPasswordLength?
number
8
maxPasswordLength?
number
128
sendResetPassword?
function
-
onPasswordReset?
function
-
resetPasswordTokenExpiresIn?
number
3600
password?
object
-

On this page