Files
OJ2/docker/compose.school.yml
yuetsh face92a5dc fix(登录): 默认不再把 Django 的 pbkdf2 升级成 argon2 —— 这是道单向门
试跑第一天就出事了:在 oj2 上登录过的账号,回旧站 oj.xuyue.cc 登不上,WS 也连不上
(旧站的 Channels 认 session,没登录自然连不上,两个症状同一个根因)。

`routes/auth.ts` 原来在登录成功后把 pbkdf2 哈希重算成 argon2id 写回库。问题是:

- Bun 写出来的是 `$argon2id$v=19$…`,Django 存 argon2 是 `argon2$argon2id$v=19$…`
  (多一个算法标签、没有开头的 `$`)。Django 按 `$` 切第一段当算法名,拿到空串,认不出。
- 更彻底的一点:旧后端的 pyproject.toml 里**根本没有 argon2-cffi**,
  格式对了也验不了。

所以这不只是双跑的问题 —— 一次性切换后的回滚窗口内同样成立:学生登录过新站,
回滚之后就登不上了。演练时比对的是表结构「逐列一致」,比不出这种语义上的单向门。

改成 `config.passwordHashUpgrade` 控制,**默认关闭**,并在两份 compose 的
environment 里显式声明 `PASSWORD_HASH_UPGRADE`(原来根本没透传,想开也开不了)。
等确定不会再回滚了再打开。

## 验证(真库真容器,不是看代码)

schema.sql 起库 + 造一个 Django 格式的 pbkdf2 用户(密码已知),跑新栈实测:

- 默认形态:登录 200,库里的哈希**仍是** `pbkdf2_sha256$260000$…`,容器里
  PASSWORD_HASH_UPGRADE 为空
- 对照组 PASSWORD_HASH_UPGRADE=true:登录 200,哈希变成 `$argon2id$v=19$m=655…`
  —— 正是生产库现在的样子,锁死可复现

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-16 09:57:43 -06:00

119 lines
4.0 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 机房。**这里没有数据库** —— 连的是服务器那台的 5445见 compose.debian.yml
#
# docker compose -f docker/compose.school.yml --env-file docker/.env.school up -d --build
#
# 两个站点共用一个库,但各有各的 Redis、判题沙箱和后端。这意味着
#
# - 判题队列是每站独立的BullMQ 在本地 Redis 上),学生在哪边提交就在哪边判,
# 和旧后端的 Dramatiq 拓扑一致;
# - WebSocket 推送也走本地 Redis pub/sub所以只推得到连在**本站**的学生。
# 旧后端的 Channels 也是这样,不是回归;
# - **切换那天两边都要切。** 只切一边的话,另一边的旧后端仍在读写同一个库,
# 而库结构已经按新后端迁过了。
#
# ⚠️ `DATA_DIR` 默认值 `../data` 解析出来是 **`OJ2/data`**,不是机房部署目录的 `data/`。
# 测试点(`data/backend/test_case`)和题面图片(`data/backend/public/upload`)都在旧目录里,
# 不设 `DATA_DIR` 就会挂一堆空目录上去:判题全错、图片 404。**沿用旧数据必须设它。**
services:
oj-redis:
image: redis:7-alpine
container_name: oj-redis
restart: always
volumes:
- ${DATA_DIR:-../data}/redis:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 10
oj-judge:
image: registry.cn-hongkong.aliyuncs.com/oj-image/judge:1.6.1
container_name: oj-judge
restart: always
read_only: true
cap_drop:
- SETPCAP
- MKNOD
- NET_BIND_SERVICE
- SYS_CHROOT
- SETFCAP
- FSETID
tmpfs:
- /tmp
volumes:
- ${DATA_DIR:-../data}/backend/test_case:/test_case:ro
# 并行试跑时必须单独设 JUDGE_STATE_DIR否则新旧两个 judger 共用一个运行目录
- ${JUDGE_STATE_DIR:-${DATA_DIR:-../data}/judge_server}/log:/log
- ${JUDGE_STATE_DIR:-${DATA_DIR:-../data}/judge_server}/run:/judger
environment:
SERVICE_URL: http://oj-judge:8080
BACKEND_URL: http://oj-api:3000/api/judge-server/heartbeat
TOKEN: ${OJ2_JUDGE_TOKEN:?请在 env 文件里设置 OJ2_JUDGE_TOKEN}
# 机房机器内存宽裕,判题给足
mem_limit: 2g
oj-api:
build: &build
context: ..
dockerfile: docker/Dockerfile
target: api
image: oj2-api:latest
container_name: oj-api
restart: always
depends_on:
oj-redis:
condition: service_healthy
volumes:
- ${DATA_DIR:-../data}/backend:/data
environment: &api-env
# 库在服务器上走公网。DB_HOST 默认值就是服务器地址,换机器改 env 文件
DATABASE_URL: postgres://onlinejudge:${POSTGRES_PASSWORD:?}@${DB_HOST:-150.158.29.156}:${DB_PORT:-5445}/onlinejudge
REDIS_URL: redis://oj-redis:6379
JUDGE_SERVER_URL: http://oj-judge:8080
JUDGE_SERVER_TOKEN: ${OJ2_JUDGE_TOKEN:?}
JUDGE_CONCURRENCY: ${JUDGE_CONCURRENCY:-4}
AI_KEY: ${AI_KEY:-}
# 机房走 http 直连 IP没有 TLS。带 Secure 的 Cookie 浏览器不会回传,
# 学生会「登录成功但立刻又是未登录」。这里必须是 false。
PASSWORD_HASH_UPGRADE: ${PASSWORD_HASH_UPGRADE:-}
COOKIE_SECURE: ${COOKIE_SECURE:-false}
healthcheck:
test: ["CMD", "oj2-api", "healthcheck"]
interval: 30s
timeout: 3s
retries: 3
start_period: 10s
mem_limit: 4g
oj-worker:
build: *build
image: oj2-api:latest
container_name: oj-worker
restart: always
depends_on:
- oj-api
volumes:
- ${DATA_DIR:-../data}/backend:/data
environment: *api-env
command: ["oj2-api", "worker"]
mem_limit: 2g
oj-web:
build:
context: ..
dockerfile: docker/Dockerfile
target: web
image: oj2-web:latest
container_name: oj-web
restart: always
depends_on:
- oj-api
volumes:
- ${DATA_DIR:-../data}/backend/log:/data/log
ports:
# 并行试跑时换一个端口81 还被旧 backend 占着
- "${WEB_PORT:-81}:8000"
mem_limit: 256m