速率限制

Better Auth 内置了速率限制器,以帮助管理流量和防止滥用。在生产模式下,默认的速率限制设置为:

【Better Auth includes a built-in rate limiter to help manage traffic and prevent abuse. By default, in production mode, the rate limiter is set to:】

  • 窗口:60秒
  • 最大请求次数:100次请求

使用 auth.api 发起的服务器端请求不受速率限制影响。速率限制只适用于客户端发起的请求。

你可以通过将 rateLimit 对象传递给 betterAuth 函数来轻松自定义这些设置。

【You can easily customize these settings by passing the rateLimit object to the betterAuth function.】

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

export const auth = betterAuth({
    rateLimit: {
        window: 10, // time window in seconds
        max: 100, // max requests in the window
    },
})

在开发模式下,默认禁用速率限制。要启用它,请将 enabled 设置为 true

【Rate limiting is disabled in development mode by default. In order to enable it, set enabled to true:】

auth.ts
export const auth = betterAuth({
    rateLimit: {
        enabled: true,
        //...other options
    },
})

除了默认设置外,Better Auth 还为特定路径提供自定义规则。例如:

  • /sign-in/email:在 10 秒内限制为 3 次请求。

【In addition to the default settings, Better Auth provides custom rules for specific paths. For example:

  • /sign-in/email: Is limited to 3 requests within 10 seconds.】

此外,插件还可以为特定路径定义自定义规则。例如,twoFactor 插件有以下自定义规则:

  • /two-factor/verify:在 10 秒内限制最多 3 次请求。

【In addition, plugins also define custom rules for specific paths. For example, twoFactor plugin has custom rules:

  • /two-factor/verify: Is limited to 3 requests within 10 seconds.】

这些自定义规则确保敏感操作受到更严格的限制保护。

【These custom rules ensure that sensitive operations are protected with stricter limits.】

配置速率限制

【Configuring Rate Limit】

连接 IP 地址

【Connecting IP Address】

速率限制使用连接的 IP 地址来跟踪用户发出的请求次数。默认检查的头信息是 x-forwarded-for,这在生产环境中很常用。如果你使用不同的头信息来跟踪用户的 IP 地址,则需要指定它。

【Rate limiting uses the connecting IP address to track the number of requests made by a user. The default header checked is x-forwarded-for, which is commonly used in production environments. If you are using a different header to track the user's IP address, you'll need to specify it.】

auth.ts
export const auth = betterAuth({
    //...other options
    advanced: {
        ipAddress: {
          ipAddressHeaders: ["cf-connecting-ip"], // Cloudflare specific header example
      },
    },
    rateLimit: {
        enabled: true,
        window: 60, // time window in seconds
        max: 100, // max requests in the window
    },
})

IPv6 地址支持

【IPv6 Address Support】

Better Auth 会自动规范化 IPv6 地址,以防止攻击者使用同一 IPv6 地址的不同表示形式(例如 2001:db8::12001:0db8:0000:0000:0000:0000:0000:0001)进行绕过攻击。这确保在速率限制时,同一 IPv6 地址的所有表示形式都会被视为相同。

【Better Auth automatically normalizes IPv6 addresses to prevent bypass attacks where attackers use different representations of the same IPv6 address (e.g., 2001:db8::1 vs 2001:0db8:0000:0000:0000:0000:0000:0001). This ensures that all representations of the same IPv6 address are treated as the same for rate limiting purposes.】

此外,IPv4 映射的 IPv6 地址(例如 ::ffff:192.0.2.1)会被自动转换为其 IPv4 形式(192.0.2.1),以防止攻击者通过在 IPv4 和 IPv6 表示间切换来绕过速率限制。

【Additionally, IPv4-mapped IPv6 addresses (e.g., ::ffff:192.0.2.1) are automatically converted to their IPv4 form (192.0.2.1) to prevent attackers from bypassing rate limits by switching between IPv4 and IPv6 representations.】

IPv6 子网速率限制

【IPv6 Subnet Rate Limiting】

默认情况下,IPv6 地址会单独限制速率(使用完整的 /128 地址)。然而,由于 IPv6 通常会为单个用户分配较大的地址块,攻击者可能通过轮换使用其分配的多个 IPv6 地址来绕过速率限制。

【By default, IPv6 addresses are rate limited individually (using the full /128 address). However, since IPv6 typically allocates large address blocks to single users, attackers could potentially bypass rate limits by rotating through multiple IPv6 addresses from their allocation.】

为防止这种情况,你可以将速率限制配置为应用于 IPv6 子网,而不是单个地址:

【To prevent this, you can configure rate limiting to apply to IPv6 subnets instead of individual addresses:】

auth.ts
export const auth = betterAuth({
    //...other options
    advanced: {
        ipAddress: {
            ipv6Subnet: 64, // Rate limit by /64 subnet instead of individual addresses
        },
    },
    rateLimit: {
        enabled: true,
        window: 60,
        max: 100,
    },
})

常见的 IPv6 子网前缀长度:

  • 128(默认):单个 IPv6 地址 - 限制最严格
  • 64:/64 子网 - 典型的家庭/企业分配
  • 48:/48 子网 - 较大网络分配
  • 32:/32 子网 - ISP 级别分配

【Common IPv6 subnet prefix lengths:

  • 128 (default): Individual IPv6 address - most restrictive
  • 64: /64 subnet - typical home/business allocation
  • 48: /48 subnet - larger network allocation
  • 32: /32 subnet - ISP-level allocation】

IPv6 子网配置仅影响 IPv6 地址。IPv4 地址始终单独进行速率限制。

速率限制窗口

【Rate Limit Window】

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

export const auth = betterAuth({
    //...other options
    rateLimit: {
        window: 60, // time window in seconds
        max: 100, // max requests in the window
    },
})

你也可以为特定路径传递自定义规则。

【You can also pass custom rules for specific paths.】

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

export const auth = betterAuth({
    //...other options
    rateLimit: {
        window: 60, // time window in seconds
        max: 100, // max requests in the window
        customRules: {
            "/sign-in/email": {
                window: 10,
                max: 3,
            },
            "/two-factor/*": async (request)=> {
                // custom function to return rate limit window and max
                return {
                    window: 10,
                    max: 3,
                }
            }
        },
    },
})

如果你想为特定路径禁用速率限制,你可以将其设置为 false,或在自定义规则函数中返回 false

【If you like to disable rate limiting for a specific path, you can set it to false or return false from the custom rule function.】

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

export const auth = betterAuth({
    //...other options
    rateLimit: {
        customRules: {
            "/get-session": false,
        },
    },
})

存储

【Storage】

默认情况下,速率限制数据存储在内存中,这可能不适用于许多使用场景,特别是在无服务器环境中。为了解决这个问题,你可以使用数据库、二级存储或自定义存储来存储速率限制数据。

【By default, rate limit data is stored in memory, which may not be suitable for many use cases, particularly in serverless environments. To address this, you can use a database, secondary storage, or custom storage for storing rate limit data.】

使用数据库

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

export const auth = betterAuth({
    //...other options
    rateLimit: {
        storage: "database",
        modelName: "rateLimit", //optional by default "rateLimit" is used
    },
})

确保运行 migrate 来在你的数据库中创建速率限制表。

【Make sure to run migrate to create the rate limit table in your database.】

npx @better-auth/cli migrate

使用二级存储

如果已经配置了二级存储,你可以使用它来存储速率限制数据。

【If a Secondary Storage has been configured you can use that to store rate limit data.】

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

export const auth = betterAuth({
    //...other options
    rateLimit: {
		storage: "secondary-storage"
    },
})

自定义存储

如果上述解决方案都不适合你的使用场景,你可以实现一个 customStorage

【If none of the above solutions suits your use case you can implement a customStorage.】

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

export const auth = betterAuth({
    //...other options
    rateLimit: {
        customStorage: {
            get: async (key) => {
                // get rate limit data
            },
            set: async (key, value) => {
                // set rate limit data
            },
        },
    },
})

处理速率限制错误

【Handling Rate Limit Errors】

当请求超过速率限制时,Better Auth 会返回以下头信息:

【When a request exceeds the rate limit, Better Auth returns the following header:】

  • X-Retry-After:用户可以再次发出请求之前的等待秒数。

要在客户端处理速率限制错误,你可以全局管理它们,也可以按每个请求管理。由于 Better Auth 客户端是基于 Better Fetch 封装的,你可以传递 fetchOptions 来处理速率限制错误

【To handle rate limit errors on the client side, you can manage them either globally or on a per-request basis. Since Better Auth clients wrap over Better Fetch, you can pass fetchOptions to handle rate limit errors】

全球处理

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

export const authClient = createAuthClient({
    fetchOptions: {
        onError: async (context) => {
            const { response } = context;
            if (response.status === 429) {
                const retryAfter = response.headers.get("X-Retry-After");
                console.log(`Rate limit exceeded. Retry after ${retryAfter} seconds`);
            }
        },
    }
})

按请求处理

auth-client.ts
import { authClient } from "./auth-client";

await authClient.signIn.email({
    fetchOptions: {
        onError: async (context) => {
            const { response } = context;
            if (response.status === 429) {
                const retryAfter = response.headers.get("X-Retry-After");
                console.log(`Rate limit exceeded. Retry after ${retryAfter} seconds`);
            }
        },
    }
})

架构

【Schema】

如果你使用数据库来存储速率限制数据,你需要这个模式:

【If you are using a database to store rate limit data you need this schema:】

表名:rateLimit

【Table Name: rateLimit

Field NameTypeKeyDescription
idstringDatabase ID
keystring-Unique identifier for each rate limit key
countinteger-Time window in seconds
lastRequestbigint-Max requests in the window

On this page