- replace plaintext login and unlock requests with RSA-OAEP/AES-GCM encrypted payloads - add login challenge replay protection, production RSA key validation, and auth tests - wire compose to environment-driven dev/prod settings without committing local secrets - update setup-config smoke scripts and Postman docs for encrypted login - add visit schedule migrations/tests and update study/subject setup workflows
8.5 KiB
CTMS 分支环境安装配置指南
本文定义 dev、main、release 三类分支对应的推荐部署环境、配置文件、初始化步骤与验证命令。分支本身不会自动切换运行模式,实际模式由后端环境变量 ENV 决定。
分支与环境映射
| 分支 | 分支定位 | 推荐环境 | 后端 ENV |
用途 |
|---|---|---|---|---|
dev |
日常开发与集成 | 开发环境 | development |
功能开发、联调、自测、内部集成 |
main |
下一版本候选 | 预发布 / 验收环境 | production |
回归测试、验收、发布候选验证 |
release |
当前稳定生产线 | 生产环境 | production |
正式生产部署、生产 hotfix |
推广路径保持为:
feature/* -> dev -> main -> release
不要把 release 当作日常开发分支使用。main 应只接收已经准备进入候选版本范围的变更。
公共前置条件
所有环境都需要:
- Docker 与 Docker Compose
- 可写的
pg_data/数据目录 - 端口
8888、8000、5432未被占用 - 后端镜像可安装
backend/requirements.txt中的依赖 - 前端镜像可执行
npm ci与npm run build
当前 compose 服务拓扑:
nginx -> backend -> db
对外入口:
- 前端:
http://localhost:8888 - 后端 API:同域
/api/v1/* - 健康检查:
http://localhost:8888/health
dev 分支:开发环境
dev 默认用于本地开发和内部集成,推荐使用 ENV=development。
1. 切换分支
git checkout dev
git pull --rebase origin dev
2. 配置 .env
根目录 .env 不提交到仓库。开发环境推荐:
COMPOSE_PROJECT_NAME=ctms_dev
ENV=development
JWT_SECRET_KEY=dev-secret
LOGIN_RSA_KEY_ID=default
LOGIN_RSA_PRIVATE_KEY=
说明:
ENV=development会启用开发行为。- 未配置
LOGIN_RSA_PRIVATE_KEY时,后端启动后会生成临时 RSA 私钥。 - 后端重启后临时公钥会变化,已有登录页应刷新后重新登录。
JWT_SECRET_KEY=dev-secret只允许本地开发使用。
3. 启动
docker compose up -d --build backend nginx
如果需要首次启动完整栈:
docker compose up -d --build
4. 开发模式行为
development 模式下:
- FastAPI
debug=True - 应用启动时会执行
Base.metadata.create_all - 应用启动时会确保默认管理员存在
- 未配置 RSA 私钥时允许临时生成
这些行为只适合开发,不适合生产。
5. 验证
docker compose ps
docker compose exec backend python -c "from app.core.config import settings; print(settings.ENV)"
curl -i http://127.0.0.1:8888/health
curl -i http://127.0.0.1:8888/api/v1/auth/login-key
预期:
ENV=development
GET /health -> 200
GET /api/v1/auth/login-key -> 200, key_id=default
main 分支:预发布 / 验收环境
main 是下一正式版本候选分支,应按生产模式运行,但不直接承载正式生产流量。
1. 切换分支
git checkout main
git pull --rebase origin main
2. 配置 .env
预发布环境应使用 ENV=production,并配置独立于生产的密钥:
COMPOSE_PROJECT_NAME=ctms_staging
ENV=production
JWT_SECRET_KEY=<staging-strong-random-secret>
LOGIN_RSA_KEY_ID=staging-YYYYMMDD
LOGIN_RSA_PRIVATE_KEY=<staging-rsa-private-key-pem-with-\n-escaped-newlines>
生成密钥示例:
openssl rand -hex 32
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048
要求:
JWT_SECRET_KEY不得使用dev-secret。LOGIN_RSA_PRIVATE_KEY必须固定保存,不能每次部署重新生成。- staging 私钥不得复用 production 私钥。
3. 初始化数据库
生产模式不会自动建表或自动补管理员。首次部署或迁移前执行:
docker compose run --rm backend-init
该步骤应运行 Alembic migration,并确保固定管理员账号存在。
4. 启动
docker compose up -d --build
5. 验证
docker compose config
docker compose ps
docker compose exec backend python -c "from app.core.config import settings; print(settings.ENV); print(settings.JWT_SECRET_KEY == 'dev-secret'); print(bool(settings.LOGIN_RSA_PRIVATE_KEY))"
curl -i http://127.0.0.1:8888/health
curl -i http://127.0.0.1:8888/api/v1/auth/login-key
预期:
ENV=production
JWT_SECRET_KEY == dev-secret -> False
LOGIN_RSA_PRIVATE_KEY_SET -> True
GET /health -> 200
GET /api/v1/auth/login-key -> 200
6. 验收门禁
在把 main 推进到 release 前,至少执行:
docker compose run --rm -v "$PWD/backend/tests:/code/tests:ro" backend python -m pytest
cd frontend && npm run test:unit
cd frontend && npm run type-check
cd frontend && npm run build
release 分支:生产环境
release 是正式生产稳定分支。只有正式发布和生产 hotfix 应进入该分支。
1. 切换分支
git checkout release
git pull --rebase origin release
2. 配置 .env
生产环境必须使用生产专用配置:
COMPOSE_PROJECT_NAME=ctms_prod
ENV=production
JWT_SECRET_KEY=<production-strong-random-secret>
LOGIN_RSA_KEY_ID=prod-YYYYMMDD
LOGIN_RSA_PRIVATE_KEY=<production-rsa-private-key-pem-with-\n-escaped-newlines>
要求:
.env必须只保存在部署机器或密钥管理系统中。- 不得提交
.env、私钥、JWT 密钥。 JWT_SECRET_KEY轮换会使既有 token 失效,应安排维护窗口。LOGIN_RSA_PRIVATE_KEY轮换会影响新登录密钥获取,应同步更新LOGIN_RSA_KEY_ID。
3. HTTPS 要求
登录加密依赖浏览器 WebCrypto。生产访问必须使用 HTTPS:
https://正式域名- 本地
localhost是浏览器安全上下文例外,但不能代表生产可用性
如果生产仍通过 http://服务器IP:8888 访问,前端会拒绝执行登录加密。
4. 初始化与迁移
首次部署或每次包含 migration 的发布:
docker compose run --rm backend-init
确认 migration 成功后再启动或滚动重启服务。
5. 启动
docker compose up -d --build
6. 生产验证
docker compose ps
docker compose exec backend python -c "from app.core.config import settings; print(settings.ENV); print(settings.JWT_SECRET_KEY == 'dev-secret'); print(bool(settings.LOGIN_RSA_PRIVATE_KEY)); print(settings.LOGIN_RSA_KEY_ID)"
curl -i https://<production-domain>/health
curl -i https://<production-domain>/api/v1/auth/login-key
预期:
ENV=production
JWT_SECRET_KEY == dev-secret -> False
LOGIN_RSA_PRIVATE_KEY_SET -> True
GET /health -> 200
GET /api/v1/auth/login-key -> 200
7. 多实例约束
当前登录 challenge 默认保存在后端进程内:
- 单实例、单 worker:可直接使用
- 多实例或多 worker:必须满足以下至少一项
- 使用共享缓存保存 challenge,例如 Redis
- 启用粘性会话,确保
/login-key与/login命中同一后端进程 - 将后端限制为单 worker 单副本
如果不满足,上线后可能出现偶发登录失败。
环境变量说明
| 变量 | dev | main/staging | release/production | 说明 |
|---|---|---|---|---|
COMPOSE_PROJECT_NAME |
ctms_dev |
ctms_staging |
ctms_prod |
防止不同环境容器名、网络名冲突 |
ENV |
development |
production |
production |
后端运行模式 |
JWT_SECRET_KEY |
dev-secret |
强随机 | 强随机 | JWT 签名密钥 |
LOGIN_RSA_KEY_ID |
default |
staging-YYYYMMDD |
prod-YYYYMMDD |
登录 RSA 密钥版本 |
LOGIN_RSA_PRIVATE_KEY |
空 | staging 私钥 | production 私钥 | RSA 私钥,生产模式必填 |
常见问题
登录页提示当前浏览器环境不支持安全登录加密
原因:非 HTTPS、非 localhost 的访问环境不满足 WebCrypto 安全上下文要求。
处理:
- 本地使用
http://localhost:8888 - staging/production 使用 HTTPS 域名
production 模式启动失败,提示必须配置 LOGIN_RSA_PRIVATE_KEY
原因:ENV=production 时必须提供固定 RSA 私钥。
处理:
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048
将输出 PEM 写入 .env 的 LOGIN_RSA_PRIVATE_KEY,换行使用 \n 转义。
切换分支后环境不符合预期
分支不会自动修改 .env。切换分支后应重新确认:
docker compose config
docker compose exec backend python -c "from app.core.config import settings; print(settings.ENV)"
必要时修改 .env 并重启:
docker compose up -d --build backend nginx