Multica Docs

登录与注册配置

配 Email 验证码登录、Google OAuth、注册白名单和本地测试验证码。

Multica 支持两种登录方式:Email + 验证码(默认)和 Google OAuth(可选)。登录成功后 server 签发一个 30 天有效期的 JWT cookie。这一页讲怎么配、怎么限制谁能注册、以及本地测试验证码怎么安全使用。

上面用到的环境变量的清单见 环境变量;token 怎么用、生命周期细节见 认证与令牌

Email + 验证码登录怎么工作

用户在登录页输邮箱 → server 发 6 位验证码 → 用户填回 → server 验证 → 签发 JWT cookie。是标准流程。支持两种邮件发送通道,按部署环境二选一:

Option A:Resend(公网/云端部署推荐)

  1. Resend 建账号、验证你的域名

  2. 创建 API key

  3. 设环境变量:

    RESEND_API_KEY=re_xxxxxxxxxxxxxxxx
    RESEND_FROM_EMAIL=noreply@yourdomain.com  # 必须是 Resend 已验证的域名
  4. 重启 server

Option B:SMTP relay(内网/自部署)

适合内网无法访问 api.resend.com,或者已经有内部邮件中继(Microsoft Exchange、Postfix、自部署 SendGrid 等)的场景。同时设置时 SMTP_HOST 优先级高于 RESEND_API_KEY:只要 SMTP_HOST 非空,server 一律走 SMTP 路径,即便 RESEND_API_KEY 也配着,验证码和邀请邮件也不会经过 Resend 外发出内网。

SMTP 路径覆盖大多数本地邮件服务器(特别是 Microsoft Exchange 的 receive connector)暴露的三种 relay 模式:

模式端口认证TLS
匿名内部 relay25无 —— 按 IP / 子网信任链路上无 TLS(仅限内网段)
认证提交(submission)587SMTP_USERNAME + SMTP_PASSWORDSTARTTLS,自动升级
隐式 TLS(SMTPS)465可选(SMTP_USERNAME + SMTP_PASSWORD连上即 TLS 握手 —— 端口 465 自动启用;非标准端口设 SMTP_TLS=implicit 强制开启

匿名 Exchange relay,端口 25 —— 经典的 "internal SMTP relay" / Exchange 匿名 receive connector,按可信子网放行,不要求凭据:

SMTP_HOST=exchange.internal.example.com
SMTP_PORT=25
SMTP_USERNAME=
SMTP_PASSWORD=
SMTP_TLS_INSECURE=false
RESEND_FROM_EMAIL=noreply@yourdomain.com  # 同时作为 SMTP From: 头

认证提交,端口 587 —— 需要 service account 的 relay;服务端 advertise STARTTLS 时会自动升级:

SMTP_HOST=smtp.internal.example.com
SMTP_PORT=587
SMTP_USERNAME=multica
SMTP_PASSWORD=...
SMTP_TLS_INSECURE=false        # 仅在私有 CA / 自签证书时改成 true
RESEND_FROM_EMAIL=noreply@yourdomain.com

隐式 TLS(SMTPS),端口 465 —— 适用于只提供 SMTPS、不广告 STARTTLS 的服务商(例如阿里云 / 腾讯企业邮箱)。端口 465 会自动启用隐式 TLS;非标准 SMTPS 端口设置 SMTP_TLS=implicit(别名:smtpsssl)即可强制开启:

SMTP_HOST=smtp.qiye.aliyun.com
SMTP_PORT=465                  # 465 自动启用隐式 TLS
SMTP_USERNAME=multica@yourdomain.com
SMTP_PASSWORD=...
SMTP_TLS=implicit              # 465 上可省略;在非标准 SMTPS 端口上必填
RESEND_FROM_EMAIL=noreply@yourdomain.com

**严格公网 relay(例如 Google Workspace smtp-relay.gmail.com)**还要求一个合法的 EHLO 名称。它们会拒绝来自公网 IP 的默认 localhost 问候,relay 随即断开连接——这不会在问候阶段报错,而是在后续某条命令上表现为一个不知所云的 EOFsmtp auth: EOF)。把 SMTP_EHLO_NAME 设成 relay 期望的 FQDN;它默认取机器主机名,而在容器内这通常不是合法的 FQDN:

SMTP_HOST=smtp-relay.gmail.com
SMTP_PORT=587
SMTP_EHLO_NAME=mail.yourdomain.com   # relay 接受的 FQDN;默认取(非 FQDN 的)容器主机名
RESEND_FROM_EMAIL=noreply@yourdomain.com

启动时 server 会打印当前选择的 provider 和协商出的 TLS 模式,比如 EmailService: SMTP relay exchange.internal.example.com:25 (starttls) from=noreply@example.com… smtp.qiye.aliyun.com:465 (implicit-tls) from=…(或 Resend API / DEV mode),密码不会出现在日志里。重启后没看到 SMTP 这行,说明 SMTP_HOST 没进到进程,确认下容器环境(docker compose -f docker-compose.selfhost.yml exec backend env | grep SMTP)。

两种都不配:server 不报错,但所有本该发出去的邮件只打到 server 的 stdout。本地开发方便(你从日志抄验证码),生产环境等于黑洞。

固定本地测试验证码

不要在公网可访问实例上启用固定验证码。

旧版「非 production 默认接受 888888」的行为已经移除。除非你显式配置,否则输入 888888 会和普通错误验证码一样被拒绝。

没配任何邮件后端(Resend 和 SMTP 都没设)的本地开发,应使用 server 日志里打印的随机验证码。如果你需要确定性的本地/私有自动化测试,可以把 MULTICA_DEV_VERIFICATION_CODE 设成一个 6 位数字,比如 888888,并保持 APP_ENV 为非 production:

APP_ENV=development
MULTICA_DEV_VERIFICATION_CODE=888888

APP_ENV=production 时这个快捷码会被忽略。

生产部署应保持 MULTICA_DEV_VERIFICATION_CODE 为空,并设置 APP_ENV=production。如果你用 make selfhost / docker-compose.selfhost.yml 自部署,APP_ENV 默认就是 production

怎么配 Google OAuth

可选。不配就只有 Email + 验证码登录;配了后登录页会多出「用 Google 登录」按钮。

  1. Google Cloud Console 创建一个 OAuth 2.0 client

  2. 授权的回调 URI(Authorized redirect URIs)填你的 Multica 前端地址加 /auth/callback,例如:

    https://multica.yourdomain.com/auth/callback
  3. 拿到 client ID 和 client secret 后设三个环境变量:

    GOOGLE_CLIENT_ID=xxxxx.apps.googleusercontent.com
    GOOGLE_CLIENT_SECRET=GOCSPX-xxxxxxxxxxxxxxx
    GOOGLE_REDIRECT_URI=https://multica.yourdomain.com/auth/callback
  4. 重启 server。

热生效:前端通过 /api/config 运行时读这些配置——改完只要重启 server,前端不用重建镜像、不用重新部署。

回调 URI 在 Google Console 和 GOOGLE_REDIRECT_URI 两处必须完全一致,包括协议(http vs https)、尾部斜杠、端口。不一致 Google 会拒绝整个 OAuth 流程,用户看到的错误是 redirect_uri_mismatch

怎么限制谁能注册

三层环境变量按优先级组合:

Rendering diagram…

已经登录过的老用户永远可以再次登录——signup 白名单只对首次注册生效,不拦截老用户。

  • ALLOWED_EMAILS(最高优先级)—— 显式邮箱白名单,逗号分隔。非空时只有列表里的邮箱能注册
  • ALLOWED_EMAIL_DOMAINS—— 域名白名单,逗号分隔(例如 company.io,partner.com)。
  • ALLOW_SIGNUP —— 总开关,默认 true。设 false 完全关闭注册。

三层白名单是 AND 语义,不是 OR。 很多人第一直觉是「设 ALLOWED_EMAIL_DOMAINS=company.io + ALLOW_SIGNUP=true 就是允许 company.io 和其他所有人」——不是。任何一层白名单只要设了非空值,不匹配的邮箱直接拒ALLOW_SIGNUP=true 挡不住。

要真的「允许所有人」,所有三个环境变量都留空(或 ALLOW_SIGNUP=true)。

典型配法

需求配置
公司内网,只允许 company.io 员工ALLOWED_EMAIL_DOMAINS=company.io
公司内网 + 几个外部合作者ALLOWED_EMAIL_DOMAINS=company.io + 合作者个人邮箱加到 ALLOWED_EMAILS
完全关闭自助注册,只能邀请ALLOW_SIGNUP=false
开放注册(不推荐生产用)三个都留空

关了注册还能邀请人进来吗

只对已经有 Multica 账号的人能。接受邀请那一步不检查 signup 白名单——如果对方已经注册过(比如在别的工作区),他们点链接登录就能直接接受。

但还没注册过的人,邀请救不了他们。他们接受邀请前必须先登录,登录的第一步(发验证码)会过 signup 白名单检查。如果你 ALLOW_SIGNUP=false、或他们的邮箱不在 ALLOWED_EMAILS / ALLOWED_EMAIL_DOMAINS 里,他们没法完成注册,也就没法接受邀请。

要邀请一个还没注册的外部协作者:临时把他们的邮箱加到 ALLOWED_EMAILS,等他们注册 + 接受邀请之后再把这条移掉。

邀请的创建和使用见 成员与权限

下一步

  • 环境变量 —— 这一页用到的环境变量完整定义
  • 认证与令牌 —— JWT / PAT / Daemon Token 的分类和使用
  • 故障排查 —— 验证码收不到、OAuth 报 redirect_uri_mismatch、注册被拒的常见排查