更好的 Auth 基础设施
Better Auth 的以下插件 :
dash()用于仪表板/admin API,分析跟踪以及后端点.dashClient()用于仪表板客户动作(包括审计日志查询).sentinel()安全检查和虐待保护.sentinelClient()用于浏览器指纹头+可选 PoW 自动解析.sentinelNativeClient()(从)@better-auth/infra/native)用于回放原生/博览会.
安装
npm install @better-auth/infra
# or
pnpm add @better-auth/infra
# or
bun add @better-auth/infra
服务器使用
import { betterAuth } from "better-auth";
import { dash, sentinel } from "@better-auth/infra";
export const auth = betterAuth({
// ...your Better Auth config
plugins: [
dash({
apiUrl: process.env.BETTER_AUTH_API_URL,
kvUrl: process.env.BETTER_AUTH_KV_URL,
apiKey: process.env.BETTER_AUTH_API_KEY,
}),
sentinel({
apiUrl: process.env.BETTER_AUTH_API_URL,
kvUrl: process.env.BETTER_AUTH_KV_URL,
apiKey: process.env.BETTER_AUTH_API_KEY,
security: {
credentialStuffing: {
enabled: true,
thresholds: { challenge: 3, block: 5 },
},
},
}),
],
});
客户端使用
import { createAuthClient } from "better-auth/client";
import { dashClient, sentinelClient } from "@better-auth/infra/client";
export const authClient = createAuthClient({
plugins: [
dashClient(),
sentinelClient({
autoSolveChallenge: true,
}),
],
});
// Resolve user from session or pass explicit user/org context
const auditLogs = await authClient.dash.getAuditLogs({
session: await authClient.getSession().then((r) => r.data),
organizationId: "org_123",
limit: 20,
});
本地客户端
将此插件用于您的 React Introduct / Expo app 。 这个插件设计与服务器侧哨和破折号插件一起工作,并将确保您的应用免受滥用和机器人攻击.
安装对等器
pnpm add react-native @react-native-async-storage/async-storage
# Optional, for richer device metadata in the identify payload:
pnpm add expo-constants expo-device
# Optional, secure visitor-id RNG (Expo):
pnpm add expo-crypto
# Or plain React Native — first import in the app entry:
# import "react-native-get-random-values";
@react-native-async-storage/async-storage 是可选的;如果未安装,则使用仅会话内访问者编号。 生产,安装或通过 storage (例如安全存储).
示例
import { createAuthClient } from "better-auth/client";
import { dashClient, sentinelNativeClient } from "@better-auth/infra/native";
export const authClient = createAuthClient({
baseURL: "https://your-api.example.com",
plugins: [
dashClient(),
sentinelNativeClient({
identifyUrl: process.env.EXPO_PUBLIC_BETTER_AUTH_KV_URL,
autoSolveChallenge: true,
}),
],
});
选项( E)sentinelNativeClient(中文(简体) )
identifyUrl?: string- 确定终点基准(默认为:BETTER_AUTH_KV_URL那么从洞里https://kv.better-auth.com/api/v1) (中文(简体) ).identifyOptions?: { timeout?: number; retry?: { attempts?: number; baseDelay?: number; maxDelay?: number } }— 识别 HTTP 超时( ms, 默认)1000)和 POST 重试(默认)2编号 :400编号 :600) (中文(简体) ).kvTimeout?: number—— 说 已贬值,使用时identifyOptions.timeout。 。 。 .autoSolveChallenge?: boolean何时true(违约),423包含有 PoW 挑战头的响应被解决,并用解决方案头重试一次.sentinelHeaders?: "legacy" | "modern"—— 说"modern"用途X-Sentinel-*协议头而不是遗留名称。 在服务器上匹配sentinel()默认"legacy"。 。 。 .onChallengeReceived?编号 :onChallengeSolved?编号 :onChallengeFailed?—— PoW生命周期钩(正因字符串,解出时间以ms为单位,或出错).storage?: { getItem, setItem }——稳定入驻访问者身份标识的Async密钥/值存储(推荐生产).
审计日志 APIs
dashClient() API 密码
dashClient() 添加:
authClient.dash.getAuditLogs(input)
getAuditLogs(input) 接受:
limit?: number(默认)50最大点100(中文(简体) )offset?: number(默认)0(中文(简体) )organizationId?: stringidentifier?: stringeventType?: stringuserId?: stringuser?: { id?: string | null }session?: { user?: { id?: string | null } }
解析的用户ID按此顺序确定:
input.userIddashClient({ resolveUserId })input.user?.idinput.session?.user?.id
响应形状 :
events: DashAuditLog[]total: numberlimit: numberoffset: number
示例
const session = await authClient.getSession().then((r) => r.data);
const logs = await authClient.dash.getAuditLogs({
session,
organizationId: "org_123",
limit: 50,
offset: 0,
});
要获取所有事件, 请继续使用 offset 直至 events.length < limit。 。 。 .
过滤
使用 getAuditLogs 直接在查询中过滤 :
eventType: 只返回特定事件类型(例如)user_signed_in(中文(简体) )organizationId:一个组织的范围记录identifier: 组织日志为特定标识符userId编号 :user编号 :session: 确定哪些用户的日志应被限定范围
实例:
// 1) Filter by event type
const signIns = await authClient.dash.getAuditLogs({
session,
eventType: "user_signed_in",
limit: 20,
});
// 2) Filter by org + identifier
const orgMemberEvents = await authClient.dash.getAuditLogs({
session,
organizationId: "org_123",
identifier: "[email protected]",
limit: 50,
});
// 3) Combine filters
const orgSignIns = await authClient.dash.getAuditLogs({
session,
organizationId: "org_123",
eventType: "user_signed_in",
limit: 50,
});
搜索模式
getAuditLogs 目前不显示专用全文 search 查询参数.
用于文本搜索、获取页面和过滤客户端.
const matchesText = (event: { eventType: string; eventKey: string; eventData: Record<string, unknown> }, query: string) => {
const q = query.toLowerCase().trim();
if (!q) return true;
const haystack = [
event.eventType,
event.eventKey,
JSON.stringify(event.eventData ?? {}),
]
.join(" ")
.toLowerCase();
return haystack.includes(q);
};
const page = await authClient.dash.getAuditLogs({ session, limit: 100, offset: 0 });
const filtered = page.data?.events.filter((event) => matchesText(event, "password")) ?? [];
您可以对以下对象应用相同的模式:
- 日期范围过滤( 按
createdAt(中文(简体) ) - 位置过滤( 按
location.country, (中文(简体) ),location.city页:1 - 多场大院过滤器
植入辅助器
async function getAllAuditLogs(session: unknown) {
const limit = 100;
let offset = 0;
const all: Array<{
eventType: string;
createdAt: string;
eventData: Record<string, unknown>;
}> = [];
while (true) {
const result = await authClient.dash.getAuditLogs({ session, limit, offset });
const events = result.data?.events ?? [];
all.push(...events);
if (events.length < limit) break;
offset += limit;
}
return all;
}
dash() 事件终点
这个 dash() 插件注册这些事件终点 :
getUserEvents打开GET /events/listgetAuditLogs打开GET /events/audit-logsgetEventTypes打开GET /events/types
getAuditLogs 支持查询参数 :
limit, (中文(简体) ),offset, (中文(简体) ),eventTypeorganizationId, (中文(简体) ),identifieruserId(必须匹配经认证的会话用户)
选项类型
DashOptions
apiUrl?: stringkvUrl?: stringapiKey?: stringapiOptions?: { timeout?: number }(毫秒,默认值)3000(中文(简体) )kvOptions?: { timeout?: number; retry?: { attempts?: number; baseDelay?: number; maxDelay?: number } }—— KV 超时默认1000; 重试默认值2编号 :400编号 :600apiTimeout?: number—— 说 已贬值,使用时apiOptions.timeoutkvTimeout?: number—— 说 已贬值,使用时kvOptions.timeoutactivityTracking?: { enabled?: boolean; updateInterval?: number }managedDirectorySync?: { enabled?: boolean; ssoPairing?: boolean; membershipProjection?: { enabled?: boolean; role?: string }; fieldProjection?: { enabled?: boolean } }——选择1.7+所管理的目录-同步控制平面(schema + 保留 API).enabled单靠保留表/API。 启用时, 破折号init也可以用线接接接接接接接接接接接接接接接接接接ssoPairing安装 SSOresolveUser编号 :guardProviderMutation(仅需要配对目录;需要)sso({})或更丰富的选择——裸露sso()叶子options未定义),以及membershipProjection安装 SCIMprojection.reconcileUser为org会员同步.fieldProjection(默认)false)是一个单独的选入:当启用时,每个连接仪表板映射项目会管理SCIM用户属性(和可选默认)到更好的Auth用户/成员附加字段——启用后迁移. 默认 :enabled: false, (中文(简体) ),ssoPairing: true, (中文(简体) ),membershipProjection.enabled: true, (中文(简体) ),membershipProjection.role: "member", (中文(简体) ),fieldProjection.enabled: false。必须使用scim({ managedConnections })对管理模式; 不影响或替换遗留的 SCIM 目录预-1.7 同步.
dash() 不再接受监控安全配置.
SentinelOptions
apiUrl?: stringkvUrl?: stringapiKey?: stringapiOptions?: { timeout?: number }- 与DashOptionskvOptions?: { timeout?: number; retry?: { attempts?: number; baseDelay?: number; maxDelay?: number } }- 与DashOptionsapiTimeout?: number—— 说 已贬值,使用时apiOptions.timeoutkvTimeout?: number—— 说 已贬值,使用时kvOptions.timeoutsentinelHeaders?: "legacy" | "modern"—— 说"modern"用途X-Sentinel-*协议头而不是遗留名称。 匹配客户端。 默认"legacy"。服务器前的客户端升级.security?: SecurityOptions
现在所有安全配置都属于 sentinel()。 。 。 .
DashClientOptions
resolveUserId?: ({ userId, user, session }) => string | undefined
见 Audit Log APIs 详细方法.
SentinelNativeClientOptions
从 @better-auth/infra/native。见 反应本地客户端 用于完整选项列表和使用.
移徙
如果您先前通过安全配置到 dash()移动到 sentinel()数字 :
// before
dash({
apiKey: process.env.BETTER_AUTH_API_KEY,
// no longer supported in dash
security: {
credentialStuffing: { enabled: true },
},
});
// after
dash({ apiKey: process.env.BETTER_AUTH_API_KEY });
sentinel({
apiKey: process.env.BETTER_AUTH_API_KEY,
security: {
credentialStuffing: { enabled: true },
},
});
安全说明
- 使用
sentinel()执行安全检查.dash()重点是遥测/admin行为. - 提供
BETTER_AUTH_API_KEY;没有它,哨兵就不能安全地呼叫后方API,并在启动时警告. - 如果您在代理/CDN之后运行, 请验证您的上游头信任模式( C) :
x-forwarded-for等)来避免被spoofed客户端IP归属. - 可选
sentinelHeaders: "modern"(服务器+客户端)X-Sentinel-*协议信头如此的代理重写X-Request-Id不打破识别。 先升级客户端. 启用时, 允许/ 暴露精确的X-Sentinel-*cORS 中的页眉名称( 不是通配符) .