认证系统
Better Auth 配置、OAuth 提供商设置、手机号登录、Magic Link、2FA 和微信登录集成指南
概览
项目使用 Better Auth 作为认证框架。Better Auth 是一个开源的 TypeScript 认证库,帮你处理用户注册、登录、会话管理等核心功能,无需从零实现。
- 配置位置:
products/01mvp/packages/auth/src/index.ts - 环境变量:
products/01mvp/packages/config/.env,共享兜底为packages/config/.env
登录方式一览
项目支持以下登录方式,默认已开启邮箱 + 密码登录,其余方式需配置对应环境变量后才会生效。微信登录还需要显式设置 AUTH_ENABLE_WECHAT=true。
| 登录方式 | 所需环境变量 | 默认状态 |
|---|---|---|
| 邮箱 + 密码 | BETTER_AUTH_SECRET, DATABASE_URL | 已开启 |
| GitHub OAuth | GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET | 未配置则隐藏 |
| Google OAuth | GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET | 未配置则隐藏 |
| 微信扫码 (PC) | AUTH_ENABLE_WECHAT, WECHAT_WEBSITE_APP_ID, WECHAT_WEBSITE_APP_SECRET | 未开启或未配置则隐藏 |
| 微信授权 (手机) | AUTH_ENABLE_WECHAT, WECHAT_SERVICE_ACCOUNT_APP_ID, WECHAT_SERVICE_ACCOUNT_APP_SECRET | 未开启或未配置则隐藏 |
| 微信小程序 | WECHAT_MINIPROGRAM_APP_ID, WECHAT_MINIPROGRAM_APP_SECRET | 未配置则隐藏 |
| 手机号 + 短信验证码 | SMS_PROVIDER + 对应服务商变量 | 已开启(默认推荐阿里云 PNVS) |
| Magic Link(邮件链接) | ZEABUR_EMAIL_API_KEY、EMAIL_FROM | 环境变量开启后可用 |
| 用户名登录 | 无需额外配置 | 已开启 |
| 双因素认证 (2FA) | config.auth.enableTwoFactor(代码配置) | 已开启 |
环境变量配置
基础配置
这些变量是认证系统运行的必要条件。
# 必填:Better Auth 签名密钥(至少 32 字符,用于加密 session token)
BETTER_AUTH_SECRET=your-secret-key-min-32-chars
# 站点 URL 和 API URL
VITE_WEB_URL=http://localhost:7001
VITE_SERVER_URL=http://localhost:7001/api
# 数据库连接(Drizzle 使用 PostgreSQL)
DATABASE_URL=postgresql://user:password@localhost:5432/dbname
# 可选:信任的来源域名(逗号分隔,用于 CORS 和 CSRF 防护)
TRUSTED_ORIGINS=https://app.example.com,https://www.example.com
# 可选:产品级 Cookie 前缀,默认由 @01mvp/config 提供
AUTH_COOKIE_PREFIX=01mvp-session
# 可选:跨子域名 Cookie(只在需要 SSO 时设置)
COOKIE_DOMAIN=.example.comBETTER_AUTH_SECRET 在生产环境必须使用随机生成的强密钥,绝对不要使用示例中的值。可以用 openssl rand -base64 32 生成。
默认建议让 Cookie 保持 host-only,也就是不设置 COOKIE_DOMAIN。如果同一个顶级域名下有多个产品,比如 start.example.com 和 onesay.example.com,它们应该使用不同的 AUTH_COOKIE_PREFIX,避免会话 Cookie 互相覆盖。只有同一个产品明确要在多个子域共享登录态时,才设置 COOKIE_DOMAIN。
OAuth 提供商配置
| 环境变量 | 说明 | 用于 |
|---|---|---|
GITHUB_CLIENT_ID | GitHub OAuth App 的 Client ID | GitHub 登录 |
GITHUB_CLIENT_SECRET | GitHub OAuth App 的 Client Secret | GitHub 登录 |
GOOGLE_CLIENT_ID | Google Cloud Console 的 Client ID | Google 登录 |
GOOGLE_CLIENT_SECRET | Google Cloud Console 的 Client Secret | Google 登录 |
微信登录配置
| 环境变量 | 说明 |
|---|---|
AUTH_ENABLE_WECHAT | 是否启用微信登录,默认 false |
WECHAT_WEBSITE_APP_ID | 微信开放平台网站应用 AppID(PC 扫码登录) |
WECHAT_WEBSITE_APP_SECRET | 微信开放平台网站应用 AppSecret |
WECHAT_SERVICE_ACCOUNT_APP_ID | 微信公众平台服务号 AppID(手机端授权) |
WECHAT_SERVICE_ACCOUNT_APP_SECRET | 微信公众平台服务号 AppSecret |
WECHAT_MINIPROGRAM_APP_ID | 微信小程序 AppID |
WECHAT_MINIPROGRAM_APP_SECRET | 微信小程序 AppSecret |
短信服务配置
当前模板内置阿里云 PNVS、腾讯云和 Twilio 三种短信发送适配。面向国内手机号登录时,默认推荐阿里云短信认证服务(PNVS)。
| 环境变量 | 说明 | 服务商 |
|---|---|---|
SMS_PROVIDER | 短信厂商,可选 aliyun、tencent、twilio | 通用 |
ALIBABA_CLOUD_ACCESS_KEY_ID | 阿里云 AccessKey ID | 阿里云 PNVS |
ALIBABA_CLOUD_ACCESS_KEY_SECRET | 阿里云 AccessKey Secret | 阿里云 PNVS |
ALIYUN_SMS_REGION | 阿里云 OpenAPI 地域(默认 cn-hangzhou) | 阿里云 PNVS |
TENCENT_CLOUD_SECRET_ID | 腾讯云 SecretId | 腾讯云 |
TENCENT_CLOUD_SECRET_KEY | 腾讯云 SecretKey | 腾讯云 |
TENCENT_SMS_REGION | 腾讯云地域(默认 ap-guangzhou) | 腾讯云 |
TENCENT_SMS_SDK_APP_ID | 腾讯云短信 SDK AppID | 腾讯云 |
TENCENT_SMS_SIGN_NAME | 短信签名 | 腾讯云 |
TENCENT_SMS_TEMPLATE_ID | 短信模板 ID | 腾讯云 |
TWILIO_ACCOUNT_SID | Twilio Account SID | Twilio |
TWILIO_AUTH_TOKEN | Twilio Auth Token | Twilio |
TWILIO_FROM_PHONE_NUMBER | Twilio 发送号码 | Twilio |
邮件服务配置
| 环境变量 | 说明 |
|---|---|
EMAIL_FROM | 发件人邮箱地址(用于验证邮件、Magic Link 等) |
ZEABUR_EMAIL_API_KEY | Zeabur Email API 密钥 |
认证相关变量优先写在 products/01mvp/packages/config/.env。复制产品示例文件作为起点:cp products/01mvp/packages/config/.env.example products/01mvp/packages/config/.env
双因素认证 (2FA)
项目支持基于 TOTP(如 Google Authenticator)的双因素认证,通过 Better Auth 的 twoFactor 插件实现。在 config.auth.enableTwoFactor 中控制开关(默认 true)。
详细的 2FA 配置、数据库模型和客户端集成说明,见 双因素认证。
管理员角色
项目的管理员系统和细粒度权限(SUPER_ADMIN / OPERATION_ADMIN)是安全基础设施的一部分。角色定义、权限列表和代码用法详见 管理员系统。
Better Auth 插件一览
项目预装了以下 Better Auth 插件,开箱即用:
| 插件 | 说明 |
|---|---|
admin | 管理员角色和权限管理 |
magicLink | 邮件魔法链接登录(无密码) |
openAPI | 自动生成 OpenAPI 文档 |
twoFactor | 双因素认证(TOTP) |
username | 用户名登录支持 |
phoneNumber | 手机号 + 短信验证码登录 |
wechatOAuth(自定义) | 微信 OAuth 登录(自定义插件) |
在代码中使用
客户端:获取当前用户
在 React 组件中使用 useAuth hook 获取当前登录状态:
import { useAuth } from "@01mvp/auth/react/tanstack-start/hooks";
export function UserProfile() {
const { user, isPending } = useAuth();
if (isPending) return <div>加载中...</div>;
if (!user) return <div>未登录</div>;
return (
<div>
<p>用户名: {user.name}</p>
<p>邮箱: {user.email}</p>
</div>
);
}客户端:调用登录 API
使用 authClient 发起各种认证操作:
import { authClient } from "@/lib/auth/client";
// 邮箱密码登录
await authClient.signIn.email({
email: "[email protected]",
password: "password123",
});
// GitHub 登录(跳转到 GitHub 授权页)
await authClient.signIn.social({ provider: "github" });
// 手机号验证码登录
await authClient.phoneNumber.sendOtp({ phoneNumber: "+8613800138000" });
await authClient.phoneNumber.verify({ phoneNumber: "+8613800138000", code: "123456" });
// Magic Link 登录
await authClient.signIn.magicLink({ email: "[email protected]" });
// 登出
await authClient.signOut();服务端:在 API 路由和 Server Components 中
使用 getSession 获取服务端会话(已自动缓存):
import { getSession } from "@/modules/shared/auth/lib/server";
// 在 Server Component 中
export default async function DashboardPage() {
const session = await getSession();
if (!session) {
redirect("/auth/login");
}
return <div>欢迎, {session.user.name}</div>;
}
// 在 API 路由中
export async function GET() {
const session = await getSession();
if (!session) {
return Response.json({ error: "Unauthorized" }, { status: 401 });
}
// ... 业务逻辑
}服务端:权限检查
import { isAdmin, hasPermission, AdminPermission } from "@01mvp/auth";
import { getSession } from "@/modules/shared/auth/lib/server";
export async function GET() {
const session = await getSession();
if (!session || !isAdmin(session.user)) {
return Response.json({ error: "Forbidden" }, { status: 403 });
}
// 管理员逻辑
}常见问题
各登录方式接入指南
Google OAuth
Google Cloud Console OAuth 2.0 接入指南。
GitHub OAuth
GitHub OAuth App 接入指南。
微信登录
微信开放平台扫码登录、服务号授权和小程序登录集成指南。
手机号登录
短信验证码登录和注册配置指南。
Magic Link 登录
无密码邮件链接登录配置指南。
相关资源
这篇文档有问题?