速率限制
如何限制用户在给定时间段内对服务器发起的请求次数。
Better Auth 包含内置的速率限制器,以帮助管理流量和防止滥用。默认情况下,在生产模式下,速率限制器设置为:
- 时间窗口:60 秒
- 最大请求数:100 次请求
使用 auth.api 发起的服务器端请求不受速率限制影响。速率限制只适用于客户端发起的请求。
您可以通过将 rateLimit 对象传递给 betterAuth 函数轻松自定义这些设置。
import { betterAuth } from "better-auth";
export const auth = betterAuth({
rateLimit: {
window: 10, // 时间窗口,单位秒
max: 100, // 窗口内最大请求数
},
})开发模式下默认禁用速率限制。若想启用,请将 enabled 设置为 true:
import { betterAuth } from "better-auth";
export const auth = betterAuth({
rateLimit: {
enabled: true,
//...其他选项
},
})除默认设置外,Better Auth 还为特定路径提供了自定义规则。例如:
/sign-in/email:在 10 秒内限制最多 3 次请求。
此外,插件也为特定路径定义了自定义规则。例如,twoFactor 插件有如下规则:
/two-factor/verify:在 10 秒内限制最多 3 次请求。
这些自定义规则确保敏感操作受到更严格的限制保护。
配置速率限制
连接 IP 地址
速率限制通过连接的 IP 地址来跟踪用户发起的请求数量。默认检查的请求头为 x-forwarded-for,这在生产环境中常用。如果您使用其他请求头来跟踪用户的 IP 地址,则需要指定它。
import { betterAuth } from "better-auth";
export const auth = betterAuth({
//...其他选项
advanced: {
ipAddress: {
ipAddressHeaders: ["cf-connecting-ip"], // Cloudflare 特定请求头示例
},
},
rateLimit: {
enabled: true,
window: 60, // 时间窗口,单位秒
max: 100, // 窗口内最大请求数
},
})IPv6 地址支持
Better Auth 会自动规范 IPv6 地址,以防止攻击者通过使用同一 IPv6 地址的不同表示形式绕过限制(例如 2001:db8::1 与 2001:0db8:0000:0000:0000:0000:0000:0001)。这样可以确保对于速率限制来说,所有同一 IPv6 地址的表现形式都被视为相同。
此外,IPv4 映射的 IPv6 地址(例如 ::ffff:192.0.2.1)会自动转换为它们的 IPv4 形式(192.0.2.1),防止攻击者通过在 IPv4 和 IPv6 表示之间切换绕过速率限制。
IPv6 子网速率限制
默认情况下,IPv6 地址以单个地址(/128)为单位进行速率限制。但由于 IPv6 通常会分配给单个用户较大的地址块,攻击者可以在其分配的多个 IPv6 地址间轮换,从而绕过速度限制。
为防止这种情况,您可以配置速率限制应用于 IPv6 子网,而不是单个地址:
export const auth = betterAuth({
//...其他选项
advanced: {
ipAddress: {
ipv6Subnet: 64, // 按 /64 子网而非单个地址进行速率限制
},
},
rateLimit: {
enabled: true,
window: 60,
max: 100,
},
})常见 IPv6 子网前缀长度:
128(默认):单个 IPv6 地址 - 最严格64:/64 子网 - 典型家庭/企业分配48:/48 子网 - 较大网络分配32:/32 子网 - ISP 级分配
IPv6 子网配置仅影响 IPv6 地址。IPv4 地址始终以单个地址进行速率限制。
速率限制时间窗口
import { betterAuth } from "better-auth";
export const auth = betterAuth({
//...其他选项
rateLimit: {
window: 60, // 时间窗口,单位秒
max: 100, // 窗口内最大请求数
},
})您也可以为特定路径传递自定义规则。
import { betterAuth } from "better-auth";
export const auth = betterAuth({
//...其他选项
rateLimit: {
window: 60, // 时间窗口,单位秒
max: 100, // 窗口内最大请求数
customRules: {
"/sign-in/email": {
window: 10,
max: 3,
},
"/two-factor/*": async (request)=> {
// 自定义函数用于返回速率限制窗口和最大请求数
return {
window: 10,
max: 3,
}
}
},
},
})如果想要禁用特定路径的速率限制,可以设置为 false,或者自定义规则函数返回 false。
import { betterAuth } from "better-auth";
export const auth = betterAuth({
//...其他选项
rateLimit: {
customRules: {
"/get-session": false,
},
},
})存储
默认情况下,速率限制数据存储在内存中,这可能不适合许多用例,尤其是在无服务器环境中。为此,您可以使用数据库、二级存储或自定义存储来存储速率限制数据。
使用数据库
import { betterAuth } from "better-auth";
export const auth = betterAuth({
//...其他选项
rateLimit: {
storage: "database",
modelName: "rateLimit", // 可选,默认使用 "rateLimit"
},
})请确保运行 migrate 命令在数据库中创建速率限制表:
npx auth@latest migratemigrate 命令仅在使用内置的 Kysely 适配器时有效。如果您使用 Prisma、Drizzle 或其他 ORM,请先执行 npx auth@latest generate,然后通过您使用的 ORM 迁移工具应用 schema。详情请参阅 Better Auth CLI。
使用二级存储
如果已经配置了二级存储,您可以使用它来存储速率限制数据。
import { betterAuth } from "better-auth";
export const auth = betterAuth({
//...其他选项
rateLimit: {
storage: "secondary-storage"
},
})自定义存储
如果上述方式都不适合您的用例,您可以实现一个 customStorage。
import { betterAuth } from "better-auth";
export const auth = betterAuth({
//...其他选项
rateLimit: {
customStorage: {
get: async (key) => {
// 获取速率限制数据
},
set: async (key, value) => {
// 设置速率限制数据
},
},
},
})处理速率限制错误
当请求超过速率限制时,Better Auth 会返回以下响应头:
X-Retry-After:距离用户可再次发起请求的秒数。
在客户端处理速率限制错误时,您可以全局处理或者针对单个请求分别处理。因为 Better Auth 客户端封装了 Better Fetch,您可以传递 fetchOptions 来处理速率限制错误。
全局处理
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(`超过速率限制。请在 ${retryAfter} 秒后重试`);
}
},
}
})单请求处理
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(`超过速率限制。请在 ${retryAfter} 秒后重试`);
}
},
}
})数据库表结构
如果您使用数据库存储速率限制数据,需要以下表结构:
表名:rateLimit