身份认证与邮件
配置 Better Auth、Google OAuth、验证邮件、密码重置和联系表单投递。
VibeAny 使用以 PostgreSQL 为存储的 Better Auth。它支持需要邮箱验证的邮箱和密码登录,以及可选的 Google OAuth 和 Google One Tap。身份认证邮件与联系表单共用同一个 Resend 或 SMTP 适配器。
当前使用的身份认证实现不是 Supabase Auth。不要在这套配置中添加 Supabase 公开身份认证变量。
身份认证路由
路由组不会出现在公开 URL 中。英文的规范页面如下:
| 用途 | 路由 |
|---|---|
| 登录 | /en/login |
| 注册 | /en/signup |
| 请求重置密码 | /en/forgot-password |
| 设置新密码 | /en/reset-password |
| 验证邮箱地址 | /en/verify-email |
| Better Auth API | /api/auth/* |
同样的页面路径也适用于 /zh 和 /es。/dashboard 和 /account 受到保护;匿名请求会重定向到对应语言的登录页,并携带安全的返回路径。
邮箱和密码
启动本地数据库和 Mailpit:
docker compose up -d db mailpit生成签名密钥:
openssl rand -base64 32配置 .env.local:
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/vibeany
BETTER_AUTH_SECRET=<generated-secret>
NEXT_PUBLIC_ENABLE_EMAIL_AUTH=true
NEXT_PUBLIC_SITE_URL=http://localhost:3000
NEXT_PUBLIC_APP_URL=http://localhost:3000执行迁移并启动应用:
npm run db:migrate
npm run dev邮箱和密码行为包括:
- 使用 cost 12 的 bcrypt 生成密码 hash
- 登录前必须完成邮箱验证
- 通过已配置的邮件适配器投递密码重置邮件
- 支持将账户与受信任的 Google 账户关联
- 支持用户自行删除账户
当 NEXT_PUBLIC_ENABLE_EMAIL_AUTH 为 false 时,注册、忘记密码、重置密码和验证邮箱页面都会重定向到登录页。如果已经配置 Google OAuth,登录页仍可以提供 Google 登录。
身份认证基准 URL
本地开发时不要设置 BETTER_AUTH_URL,让 Better Auth 跟随实际的 localhost 源地址。生产环境中则使用规范 HTTPS 源地址:
BETTER_AUTH_URL=https://your-domain.com
NEXT_PUBLIC_SITE_URL=https://your-domain.com
NEXT_PUBLIC_APP_URL=https://your-domain.com服务端解析基准 URL 时,会依次优先使用 BETTER_AUTH_URL、NEXT_PUBLIC_APP_URL,以及生产环境中的 NEXT_PUBLIC_SITE_URL。客户端身份认证请求使用同源地址,因此预览部署不会调用另一个构建时域名。
Google OAuth
创建 Google OAuth Web Client,并注册以下本地回调 URL:
http://localhost:3000/api/auth/callback/google为每个受支持的生产源地址注册对应的 HTTPS 回调 URL。配置:
GOOGLE_CLIENT_ID=<google-web-client-id>
GOOGLE_CLIENT_SECRET=<google-web-client-secret>
NEXT_PUBLIC_GOOGLE_CLIENT_ID=<same-google-web-client-id>
NEXT_PUBLIC_ENABLE_ONE_TAP=false服务端 client ID 和密钥会启用 Google 登录方式。One Tap 还需要公开 client ID;只有普通 Google OAuth 已经在同一个源地址正常工作后,才能设置 NEXT_PUBLIC_ENABLE_ONE_TAP=true。
如果既没有完整的 Google 配置,也没有启用邮箱和密码身份认证,生产环境会拒绝启动。
可选的注册 Turnstile
要使用 Cloudflare Turnstile 保护注册流程,请同时配置两个 key:
NEXT_PUBLIC_TURNSTILE_SITE_KEY=<public-site-key>
TURNSTILE_SECRET_KEY=<server-secret-key>不要只配置其中一端。Better Auth 接受注册请求前,服务端会验证令牌。
使用 Mailpit 测试本地邮件
没有 RESEND_API_KEY 时,邮件适配器会使用 SMTP。它的本地默认值与 Docker Compose 一致:
- 主机:
localhost - 端口:
1025 - 网页收件箱:http://localhost:8025
- 默认发件地址:
onboarding@resend.dev
这不会向公网发送任何邮件。开发时请在 Mailpit 收件箱中打开验证和密码重置链接。
如果使用外部数据库,请注意设置向导不会为这一选择启动 Mailpit。请通过 docker compose up -d mailpit 显式启动。
使用 Resend 发送生产邮件
请使用 Resend 账户中已验证域名下的发件地址:
RESEND_API_KEY=<resend-api-key>
RESEND_FROM_EMAIL=auth@your-domain.com
ADMIN_EMAILS=admin@your-domain.com配置 Resend API 密钥后,适配器会通过 Resend HTTP API 发信。ADMIN_EMAILS 同时控制控制台及管理员 API 的管理员授权和联系表单收件人。这里只能填写自己控制且确实需要管理用户和积分的账户;不要仅为接收通知而加入支持别名、邮件分发列表或第三方邮箱。
如果 ADMIN_EMAILS 为空,联系表单通知会回退到 src/lib/config/brand.ts 中的 brand.emails.support,同时不会授予任何邮箱账户管理员权限。如果普通支持收件人需要与管理员不同,请在上线前拆分应用中的配置,而不是扩大 ADMIN_EMAILS 的范围。
Resend 开发发件地址可以用于受限的服务商测试,但生产环境应使用你的已验证域名和预期收件人。
使用 SMTP 发送生产邮件
要使用 SMTP 而不是 Resend,请省略 RESEND_API_KEY,并配置完整的 SMTP 变量:
SMTP_HOST=<smtp-host>
SMTP_PORT=<smtp-port>
SMTP_USER=<smtp-user>
SMTP_PASS=<smtp-password>
RESEND_FROM_EMAIL=auth@your-domain.com两种传输方式共用名为 RESEND_FROM_EMAIL 的发件地址变量。当存在任意 SMTP 值时,生产 Preflight 会要求完整的主机、端口、用户名、密码和发件地址配置。
邮件模板与语言行为
身份认证验证和重置模板定义在 src/lib/auth.ts。联系表单通知格式位于应用邮件用例中,传输方式的选择则位于 src/infrastructure/email/resend-smtp-email-adapter.ts。
系统中包含英文、中文和西班牙文身份认证消息集,但当前验证和重置回调会显式选择英文。如果产品需要按用户首选语言发信,请定制这段选择逻辑。
验收清单
验证完整的本地流程:
- 打开
/en/signup,注册一个专用测试账户。 - 确认未验证的凭据无法登录。
- 在 Mailpit 中打开验证邮件,并访问其中指向本地源地址的链接。
- 登录并打开
/en/dashboard和/en/account。 - 退出登录,确认受保护页面会重定向到登录页。
- 在
/en/forgot-password请求重置。 - 打开重置邮件,设置新密码,然后再次登录。
生产环境中,请使用专用测试收件箱和真实 HTTPS 源地址重复同一流程。确认验证和重置链接绝不会指向 localhost 或其他环境。
最后运行 npm run preflight。启用邮箱身份认证后,如果 Preflight 找不到完整的 Resend 或 SMTP 投递配置,就会失败。