创建你的第一个插件

在本指南中,我们将引导您完成创建第一个 Better Auth 插件的步骤。

本指南假设您已经 设置好 Better Auth 的基础配置,并准备好创建您的第一个插件。

规划您的想法

在开始之前,您必须明确要创建什么样的插件。

在本指南中,我们将创建一个生日插件来记录用户的出生日期。

先创建服务器插件

Better Auth 插件以成对方式运行:一个 服务器插件 和一个 客户端插件。 服务器插件构成了您认证系统的基础,而客户端插件则提供了便捷的前端 API 来与您的服务器实现进行交互。

您可以在我们的 文档 中了解更多关于服务器/客户端插件的信息。

创建服务器插件

请找到一个合适的位置来创建您的生日插件文件夹,并在其中创建一个 index.ts 文件。

index.ts

index.ts 文件中,我们将导出一个代表我们服务器插件的函数。 这将是我们稍后要添加到 auth.ts 文件插件列表中的内容。

index.ts
import { createAuthClient } from "better-auth/client";
import type { BetterAuthPlugin } from "better-auth";

export const birthdayPlugin = () =>
  ({
    id: "birthdayPlugin",
  } satisfies BetterAuthPlugin);

虽然这个插件目前没有任何功能,但从技术上讲,您已经成功创建了您的第一个插件,恭喜!🎉

定义模式

为了保存每个用户的生日数据,我们必须在 user 模型之上创建一个模式。

在此处创建模式,还允许 Better Auth 的 CLI 生成更新数据库所需的模式。

你可以在此处了解更多关于 插件模式的信息

index.ts
//...
export const birthdayPlugin = () =>
  ({
    id: "birthdayPlugin",
    schema: {
      user: {
        fields: {
          birthday: {
            type: "date", // string, number, boolean, date
            required: true, // 新记录中该字段是否为必填项。(默认值:false)
            unique: false, // 该字段是否应唯一。(默认值:false)
            references: null // 该字段是否引用另一个表。(默认值:null)
          },
        },
      },
    },
  } satisfies BetterAuthPlugin);

授权逻辑

在本示例指南中,我们将设置认证逻辑来检查并确保注册用户的年龄大于5岁。 同样的概念也可以应用于验证用户同意服务条款(TOS)或类似的情况。

为此,我们将利用 钩子(Hooks),它允许我们在某个操作执行之前之后运行代码。

index.ts
export const birthdayPlugin = () => ({
    //...
    // 在我们的场景中,我们希望编写授权逻辑,
    // 这意味着我们想要`提前`拦截它。
    hooks: {
      before: [
        {
          matcher: (context) => /* ... */,
          handler: createAuthMiddleware(async (ctx) => {
            //...
          }),
        },
      ],
    },
} satisfies BetterAuthPlugin)

在我们的场景中,我们希望匹配所有发送到注册路径的请求:

Before hook
{
  matcher: (context) => context.path.startsWith("/sign-up/email"),
  //...
}

对于我们的逻辑,我们将编写以下代码来检查用户的生日是否使其年龄超过5岁。

Imports
import { APIError } from "better-auth/api";
import { createAuthMiddleware } from "better-auth/plugins";
Before hook
{
  //...
  handler: createAuthMiddleware(async (ctx) => {
    const { birthday } = ctx.body;
    if(!(birthday instanceof Date)) {
      throw new APIError("BAD_REQUEST", { message: "Birthday must be of type Date." });
    }

    const today = new Date();
    const fiveYearsAgo = new Date(today.setFullYear(today.getFullYear() - 5));

    if(birthday >= fiveYearsAgo) {
      throw new APIError("BAD_REQUEST", { message: "User must be above 5 years old." });
    }

    return { context: ctx };
  }),
}

已授权! 🔒

我们现在已成功编写代码,确保只有年龄超过5岁的用户才能注册!

客户端插件

我们即将到达终点!🏁

现在我们已经创建了服务器插件,下一步是开发我们的客户端插件。 由于这个插件没有太多前端 API 相关的内容,所以需要做的事情不多!

首先,让我们创建 client.ts 文件:

index.ts
client.ts

然后,添加以下代码:

client.ts
import { BetterAuthClientPlugin } from "better-auth";
import type { birthdayPlugin } from "./index"; // 确保以类型方式导入服务器插件

type BirthdayPlugin = typeof birthdayPlugin;

export const birthdayClientPlugin = () => {
  return {
    id: "birthdayPlugin",
    $InferServerPlugin: {} as ReturnType<BirthdayPlugin>,
  } satisfies BetterAuthClientPlugin;
};

我们所做的是让客户端插件能够从服务器插件推断出我们模式定义的类型。

就这样!这就是生日客户端插件所需的全部内容。🎂

初始化你的插件!

clientserver 插件现在都已准备就绪,最后一步是分别将它们导入到你的 auth-client.tsserver.ts 文件中来初始化插件。

服务器端初始化

server.ts
import { betterAuth } from "better-auth";
import { birthdayPlugin } from "./birthday-plugin";
 
export const auth = betterAuth({
    plugins: [
      birthdayPlugin(),
    ]
});

客户端初始化

auth-client.ts
import { createAuthClient } from "better-auth/client";
import { birthdayClientPlugin } from "./birthday-plugin/client";
 
const authClient = createAuthClient({
    plugins: [
      birthdayClientPlugin()
    ]
});

对了,还有数据表结构!

别忘了在你的 user 表模型中添加 birthday 字段!

或者,使用 generate CLI 命令

npx @better-auth/cli@latest generate

完成

恭喜!你已经成功创建了你的第一个 Better Auth 插件。 我们强烈建议你访问我们的 插件文档 来了解更多信息。

如果你有想要与社区分享的插件,欢迎通过我们的 Discord 服务器 告诉我们, 或者提交一个 pull request, 我们可能会将其添加到 社区插件 列表中!

On this page