管理控制台的配置与访问
运行和部署独立的管理应用,提升操作员权限、强制 MFA,并配置专用域名。
与 starter 提交
7d452a6同步。
Starter 在 apps/admin 中提供了一个运维管理控制台。它是第二个 Next.js 应用,并不是面向客户的应用中的 /admin 路由。借助这条边界,你可以把控制台部署到独立的受保护域名并单独发布,同时继续共用身份验证、数据库结构、模型与服务。
本地运行
先完成 starter 的常规初始化,通过公开应用创建一个用户,然后启动管理应用:
pnpm dev:admin服务地址为 http://localhost:3001。相关命令还有:
pnpm build:admin
pnpm start:admin在 .env 中设置本地管理端域名:
NEXT_PUBLIC_ADMIN_WEB_URL=http://localhost:3001设置该值后,管理端构建会将它作为 Better Auth 的域名;但如果 shell 或部署环境明确提供了 BETTER_AUTH_URL 或 NEXT_PUBLIC_AUTH_BASE_URL,则以后者为准。NEXT_PUBLIC_ADMIN_WEB_URL 会在构建时写入产物,因此在生产环境修改后必须重新部署。
提升操作员权限
平台管理权限保存在 users.role 中,与组织内的 owner、admin 和 member 角色相互独立。
admin_ro可以进入控制台并读取运维数据。admin_rw还可以执行控制台中的写操作。
在仓库根目录提升一个已有账号:
pnpm admin:promote operator@example.com admin_rw命令默认使用 admin_rw,支持 --dry-run;当同一邮箱对应多个登录提供方时,它不会自行猜测。此时请用 --provider 精确选择账号,例如:
pnpm admin:promote operator@example.com --role admin_ro --provider google授权逻辑不会通过邮箱查找角色。服务器会用会话中的唯一 ID 或 UUID 加载数据库用户,并在每个受保护页面和 API 路由上检查数据库中的角色。
必须启用 MFA
只有管理角色还不够。每位操作员都必须在公开账户界面启用 Better Auth 双因素认证。具有管理角色但未启用 MFA 的操作员会被送到 /mfa-required;完成设置后,再通过管理应用自己的 /two-factor 验证。
只使用 Google 登录的账号需要先设置密码,Better Auth 才能启用双因素认证。公开账户界面会为这种情况显示 设置密码;设置后仍然可以继续使用 Google 登录。
管理端登录和公开应用共用带挑战校验的邮箱登录端点,因此启用验证码保护时,管理端部署也必须配置 NEXT_PUBLIC_TURNSTILE_SITE_KEY 和 TURNSTILE_SECRET_KEY。
独立部署
用同一个仓库创建第二个托管项目,并执行 pnpm build:admin。为它分配独立域名,例如 https://admin.example.com。
管理应用会加载 starter 共用的生产环境校验器,因此即使某个管理页面不直接使用某项服务,目前仍需配置完整的生产必需环境变量。先复制客户应用的生产环境变量,对照 .env.example,并遵循部署与安全中的说明;然后调整管理应用专用值:
- 沿用客户应用的
DATABASE_URL和BETTER_AUTH_SECRET; - 将
NEXT_PUBLIC_ADMIN_WEB_URL设为管理端域名(除非显式覆盖,否则管理构建也会将它用于 Better Auth URL); - 提供对管理端主机名有效的 Turnstile site/secret 密钥对;只有公开站点的 widget 配置允许该主机名时才复用原密钥;
- 选择适合产品的
ADMIN_MAX_CREDIT_GRANT上限(默认值为100000)。
公开端与管理端必须使用不同域名。管理应用会发送 noindex、nofollow、noarchive 和 no-store 响应头,并采用严格的嵌入、来源和内容安全策略。这些响应头只能减少暴露面,不能代替授权;服务器布局和每个管理 API 仍会校验角色与 MFA。
上线检查清单
- 使用
pnpm build:admin构建控制台。 - 确认管理端域名和身份验证基础 URL 指向同一个部署。
- 以
admin_ro登录,确认可以查看数据,但不能使用写操作。 - 以
admin_rw登录,完成 MFA,并测试一个可恢复的写操作。 - 确认该操作出现在
/audit。 - 确认普通用户既不能打开管理页面,也不能调用管理 API。
接下来阅读管理控制台页面与运维操作,了解当前实际提供的界面。