身份认证
Void 为你配置好 Better Auth,包括数据库连接、API 路由与客户端。从邮箱密码开始,或添加社交登录提供方。
预计阅读 5 分钟
Void 会为你的应用配置好 Better Auth,包括它的数据库连接、API 路由与客户端。
快速开始
1. 启用认证
从 void/client 导入 auth 即可自动启用邮箱密码认证。使用配置来添加社交提供方。
2. 注册与登录
使用 void/client 中预配置好的认证客户端:
import { auth } from 'void/client';
// 注册
await auth.signUp.email({
email: 'alice@example.com',
password: 'example-password-123',
name: 'Alice',
});
// 登录
await auth.signIn.email({
email: 'alice@example.com',
password: 'example-password-123',
});
3. 保护一个服务端路由
在需要登录用户的路由处理器或页面 loader 中调用 requireAuth。它返回该用户,或在请求未认证时抛出 401:
import { defineHandler } from 'void';
import { requireAuth } from 'void/auth';
export const GET = defineHandler((c) => {
const user = requireAuth(c);
return { email: user.email };
});
在页面模式的 loader 中,如果你希望允许未认证访问,请使用 getUser 或 getSession:
import { defineHandler, type InferProps } from 'void';
import { getUser } from 'void/auth';
export type Props = InferProps<typeof loader>;
export const loader = defineHandler(() => {
const user = getUser();
return { user };
});
4. 退出登录
await auth.signOut();
配置
满足以下任一条件时认证会自动开启:
- 从
void/auth导入任意内容 - 从
void/client导入auth - 在
void.config.ts中添加auth - 添加一个根级的
auth.ts文件
邮箱密码默认启用。要添加社交提供方:
{ "auth": { "providers": ["email", "google", "github"] } }
提供方凭据来自 AUTH_<PROVIDER>_CLIENT_ID 与 AUTH_<PROVIDER>_CLIENT_SECRET。cognito 还需要域名、区域与用户池 ID:设置 AUTH_COGNITO_DOMAIN、AUTH_COGNITO_REGION 与 AUTH_COGNITO_USER_POOL_ID,或在 auth.ts 中设置它们。
例如 github 使用:
AUTH_GITHUB_CLIENT_ID=
AUTH_GITHUB_CLIENT_SECRET=
客户端用法
认证客户端使用 Better Auth 在 /api/auth 的客户端 API。Void 会自动为你的框架选择客户端。
需要自定义客户端时,从 void/client 导入 createAuthClient。
服务端用法
void/auth 提供以下服务端辅助函数:
import { getSession, getUser, requireAuth } from 'void/auth';
| 函数 | 返回 |
|---|---|
getUser() |
当前的 AuthUser | null |
getSession() |
{ user, session } | null |
requireAuth(c) |
已认证的用户,否则抛出 401 |
从 void/auth 导入 AuthUser 与 AuthSession 用于类型标注。
行为
- 会话存储:认证会话使用与你应用相同的数据库。部署时如果缺少
BETTER_AUTH_SECRET,Void 会自动创建,并在后续部署中复用。本地开发无需设置密钥;若要在本地预览生产构建,请提供BETTER_AUTH_SECRET。 - 缓存:已登录请求的响应会带上
Cache-Control: no-store,浏览器缓存与共享缓存都不会保留用户数据。当路由自己设置no-store,或同时设置private与no-cache时会保留自己的策略。若要用304响应重复请求,请使用 Hono 的etag()中间件搭配private, no-cache。如果自己设置 ETag,请确保它按用户区分,否则304会复用另一个账号的页面。 - 跨源请求:来自其他源的
POST、PUT、PATCH、DELETE请求与 WebSocket 连接不会使用已登录的会话,除非该源在trustedOrigins中。 - 限流:部署在 Cloudflare 上的应用会按客户端 IP 限制认证请求次数(Better Auth 的默认值,例如每 10 秒 3 次登录尝试),每个 Worker 实例各自计数。在
auth.ts中通过rateLimit修改或关闭限制。若要在多个实例间共享同一计数,设置rateLimit: { storage: 'database' },然后对直接部署到 Cloudflare 的应用运行void db generate。
代理与端到端测试
来自同一个 IP 的所有请求共享同一个计数。以下两种常见设置会触及限制:
- 服务端为你的用户调用认证端点,例如 backend-for-frontend、来自 Vercel 或 nginx 的重写,或另一个 Worker 的
fetch,这些用户共享该服务器的 IP。 - 端到端测试对已部署的应用反复注册或登录。
不要改为从 x-forwarded-for 读取客户端 IP:任何客户端都能发送该头。给可信调用方一个密钥头,并只对携带该头的请求跳过限制:
import { defineAuth } from 'void/auth';
export default defineAuth(({ defaults, env }) => ({
...defaults,
rateLimit: {
customRules: {
'/**': (request, rule) =>
env.AUTH_TRUSTED_KEY && request.headers.get('x-auth-trusted-key') === env.AUTH_TRUSTED_KEY
? false
: rule,
},
},
}));
'/**' 匹配所有认证端点。返回 false 跳过限制,返回 rule 则为其他人保留默认限制。在 env.ts 中声明 AUTH_TRUSTED_KEY: string().optional(),并用 void secret put AUTH_TRUSTED_KEY 设置它。
自定义
高级配置请在项目根目录创建 auth.ts 并导出 defineAuth(...):
import { defineAuth } from 'void/auth';
export default defineAuth(({ defaults }) => ({
...defaults,
trustedOrigins: ['https://example.com'],
}));
defaults 已经包含了 Void 的约定。请显式扩展它,而不是期待深度合并。
数据库与迁移
认证表与应用自己的表放在一起。本地开发期间,Void 会自动创建它们。
Void 平台会自动创建认证表。直接部署到 Cloudflare 时,请把它们包含进你已提交的迁移中:
void db generate
部署前检查并提交生成的 SQL。Void 会包含你的认证配置与插件表,你不需要在 db/schema.ts 中重复它们,也不需要运行 Better Auth 的 CLI。