# 验证码 (/docs/plugins/captcha)

验证码插件



**验证码插件**通过在关键端点添加验证码验证，为您的 Better Auth 系统集成了机器人防护功能。此插件确保只有人类用户可以执行注册、登录或重置密码等操作。当前支持的提供者有：

* [Google reCAPTCHA](https://developers.google.com/recaptcha)
* [Cloudflare Turnstile](https://www.cloudflare.com/application-services/products/turnstile/)
* [hCaptcha](https://www.hcaptcha.com/)
* [CaptchaFox](https://captchafox.com/)
* [Vercel BotID](https://vercel.com/docs/botid)

<Callout type="info">
  默认端点涵盖<Link href="/docs/authentication/email-password">邮箱和密码</Link>身份验证。其他身份验证方法需要显式配置<Link href="/docs/plugins/captcha#插件选项">端点</Link>数组。Vercel BotID 还需要按照下方说明进行客户端设置。
</Callout>

## 安装 [#安装]

<Steps>
  <Step>
    ### 安装依赖（可选） [#安装依赖可选]

    如果您使用 **Vercel BotID**，请在应用中安装其 SDK：

    <CodeBlockTabs defaultValue="npm" groupId="persist-install">
      <CodeBlockTabsList>
        <CodeBlockTabsTrigger value="npm">
          npm
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="pnpm">
          pnpm
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="yarn">
          yarn
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="bun">
          bun
        </CodeBlockTabsTrigger>
      </CodeBlockTabsList>

      <CodeBlockTab value="npm">
        ```bash
        npm install botid
        ```
      </CodeBlockTab>

      <CodeBlockTab value="pnpm">
        ```bash
        pnpm add botid
        ```
      </CodeBlockTab>

      <CodeBlockTab value="yarn">
        ```bash
        yarn add botid
        ```
      </CodeBlockTab>

      <CodeBlockTab value="bun">
        ```bash
        bun add botid
        ```
      </CodeBlockTab>
    </CodeBlockTabs>
  </Step>

  <Step>
    ### 将插件添加到 **auth** 配置中 [#将插件添加到-auth-配置中]

    ```ts title="auth.ts"
    import { betterAuth } from "better-auth";
    import { captcha } from "better-auth/plugins"; // [!code highlight]

    export const auth = betterAuth({
        plugins: [
            captcha({ // [!code highlight]
                provider: "cloudflare-turnstile", // 或者 google-recaptcha、hcaptcha、captchafox // [!code highlight]
                secretKey: process.env.TURNSTILE_SECRET_KEY!, // [!code highlight]
            }), // [!code highlight]
        ],
    });
    ```
  </Step>

  <Step>
    ### 为基于令牌的提供者发送令牌 [#为基于令牌的提供者发送令牌]

    <Callout type="warning">
      现在不再需要 `x-captcha-user-remote-ip` 头 — IP 地址由服务端自动检测。
    </Callout>

    对于基于令牌的提供者，请在向受保护端点发送请求时添加验证码令牌。以下示例展示了一个 `signIn` 请求：

    ```ts
    import { authClient } from "@/lib/auth-client"

    await authClient.signIn.email({
        email: "user@example.com",
        password: "secure-password",
        fetchOptions: { // [!code highlight]
            headers: { // [!code highlight]
                "x-captcha-response": turnstileToken, // [!code highlight]
            }, // [!code highlight]
        }, // [!code highlight]
    });
    ```

    * 要在客户端实现 Cloudflare Turnstile，请参考官方 [Cloudflare Turnstile 文档](https://developers.cloudflare.com/turnstile/) 或使用类似 [react-turnstile](https://www.npmjs.com/package/@marsidev/react-turnstile) 的库。
    * 要在客户端实现 Google reCAPTCHA，请参考官方 [Google reCAPTCHA 文档](https://developers.google.com/recaptcha/intro) 或使用类似 [react-google-recaptcha](https://www.npmjs.com/package/react-google-recaptcha)（v2）和 [react-google-recaptcha-v3](https://www.npmjs.com/package/react-google-recaptcha-v3)（v3）的库。
    * 要在客户端实现 hCaptcha，请参考官方 [hCaptcha 文档](https://docs.hcaptcha.com/#add-the-hcaptcha-widget-to-your-webpage) 或使用类似 [@hcaptcha/react-hcaptcha](https://www.npmjs.com/package/@hcaptcha/react-hcaptcha) 的库。
    * 要在客户端实现 CaptchaFox，请参考官方 [CaptchaFox 文档](https://docs.captchafox.com/getting-started) 或使用类似 [@captchafox/react](https://www.npmjs.com/package/@captchafox/react) 的库。
  </Step>
</Steps>

## 提供者 [#提供者]

### Vercel BotID [#vercel-botid]

BotID 需要 Vercel 部署和客户端设置。请按照 [Vercel 的设置指南](https://vercel.com/docs/botid/get-started)，根据您的框架配置重写规则并集成客户端。Better Auth 插件不使用 `secretKey` 或 `x-captcha-response` 头：

```ts title="auth.ts"
import { checkBotId } from "botid/server";
import { betterAuth } from "better-auth";
import { captcha } from "better-auth/plugins";

export const auth = betterAuth({
    plugins: [
        captcha({
            provider: "vercel-botid",
            checkBotId,
        }),
    ],
});
```

使用 `initBotId` 时，请在实际请求路径上保护 Better Auth 的默认身份验证路由：

```ts
import { initBotId } from "botid/client/core";

initBotId({
    protect: [
        { path: "/api/auth/sign-up/email", method: "POST" },
        { path: "/api/auth/sign-in/email", method: "POST" },
        { path: "/api/auth/request-password-reset", method: "POST" },
    ],
});
```

BotID 使用浏览器中的完整请求路径。插件的 `endpoints` 选项省略了 Better Auth 的基础路径，例如 `/sign-in/email`。如果更改 `basePath` 或 `endpoints`，请确保两者保持同步。

在浏览器中初始化 BotID 后，无需验证码令牌头即可正常登录：

```ts
import { authClient } from "@/lib/auth-client";

const { data, error } = await authClient.signIn.email({
    email: "user@example.com",
    password: "secure-password",
});
```

BotID 不支持[原生 HTML 表单提交](https://vercel.com/docs/botid/form-submissions)。

本地开发[默认允许请求](https://vercel.com/docs/botid/local-development-behavior)，因此在正式环境中依赖它之前，请先在 Vercel 上验证完整流程。有关特定路由的检测级别，请参阅 [Vercel 的高级配置](https://vercel.com/docs/botid/advanced-configuration)。

## 工作原理 [#工作原理]

<Steps>
  <Step>
    此插件充当中间件：它会拦截发往已配置端点的请求（请参阅[插件选项](#plugin-options)部分中的 `endpoints`）。
  </Step>

  <Step>
    它会通过调用验证码提供者的 `/siteverify`，在服务器上验证验证码令牌。

    <Callout type="info">
      **Vercel BotID** 是个例外：它使用提供的 `checkBotId` 函数，而不是验证码令牌或 `/siteverify` 调用。
    </Callout>
  </Step>

  <Step>
    * 如果令牌缺失、被验证码提供者拒绝，或者 `/siteverify` 端点不可用，插件会返回错误并中断请求。
    * 如果令牌被验证码提供者接受，中间件会返回 `undefined`，表示允许请求继续处理。
    * 对于 **Vercel BotID**，如果 `checkBotId`（或您的自定义 `validateRequest`）判定请求来自机器人，则拒绝该请求；否则允许请求继续处理。
  </Step>
</Steps>

## 插件选项 [#插件选项]

* **`provider`（必需）**：验证码提供者。
* **`secretKey`（除 `vercel-botid` 外所有提供者均必需）**：提供者的密钥，用于服务器端验证。
* `endpoints`（可选）：选择需要 CAPTCHA 保护的路径。默认情况下，`/sign-up/email`、`/sign-in/email` 和 `/request-password-reset` 受保护，其他路径不需要 CAPTCHA。设置此项后，它会替换默认值，因此应列出所有需要保护的路径。可使用精确路径或通配符，例如 `/sign-in/*` 匹配一个路径段，`/sign-in/**` 匹配嵌套路由。
* `minScore`（可选，仅适用于 *Google ReCAPTCHA v3*）：最低分数阈值，默认值为 `0.5`。
* `siteKey`（可选，仅适用于 *hCaptcha* 和 *CaptchaFox*）：防止在一个站点密钥上签发的令牌在其他站点上被兑换。
* `siteVerifyURLOverride`（可选，仅适用于基于令牌的提供者）：覆盖 CAPTCHA 验证 URL。
* `checkBotId`（*Vercel BotID* 必需）：Vercel 服务器端检查函数，从应用中的 `botid/server` 导入。如需传入 SDK 选项，请将其包装在函数中。
* `validateRequest`（可选，仅适用于 *Vercel BotID*）：自定义验证逻辑。返回 `true` 以允许请求，返回 `false` 以拒绝请求。默认情况下，仅允许 `isBot: false` 的结果。

