Files
xiaotutongxue/deploy/prod.env.example
T
lovife 50ad577b29 fix(cors): 修复生产登录 403「Invalid CORS request」
- 根因:浏览器对**同源**的 POST/PUT/DELETE 也会带 Origin,而 Spring MVC 只看
  "请求里有没有 Origin"(Spring 7.0.9 的 DefaultCorsProcessor 没有同源短路),
  带了又不在白名单里 → 进 Controller 之前直接 403
- WebConfig 的白名单写死为 localhost/内网;注释声称"生产配置见 application-prod.yml
  的 fill.cors.allowed-origins",但该属性根本不存在、也没人读它 ——
  于是"前后端同源部署"的登录/上传/提交必然登不上(生产 2026-10-20 事故)
- 改为配置驱动:FillProperties.Cors + fill.cors.allowed-origins
  (可用 XT_CORS_ALLOWED_ORIGINS 覆盖);prod 默认
  shenxue.jxit.com / admin.shenxue.jxit.com / *.shenxue.jxit.com;
  dev 补上花生壳穿透域名(H5 走穿透时 POST 同样会被拦)
- 启动日志打印生效白名单,排障先看那一行
- 新增 CorsWhitelistTest(3 条):生产 yml 真能绑定、通配符匹配租户子域、陌生源仍被拒
- docs/09 §2.4:本站地址必须在白名单 + 反代必须传
  Host/X-Real-IP/X-Forwarded-For/X-Forwarded-Proto(缺了登录日志 IP 全是 127.0.0.1);
  交接摘要 §一·四十四 记录事故,并写清"1700+ 条 e2e 全绿为什么还是漏了"

为什么 e2e 没抓到:脚本是 Python requests,不带 Origin 头,永远走不到 CORS 分支;
本地浏览器用的 localhost 正好命中写死的 dev 白名单。唯一能暴露它的是"浏览器 + 正式域名"。

验证:生产白名单下 admin / 主域名 / t1 / t12 → 200,evil / 后缀拼接 / http → 403;
真实 RSA 登录 + Origin: https://admin.shenxue.jxit.com → 200、code=0、拿到 token;
mvn test 15/15;verify-all --quick 6/6;check-test-profile 通过。
接口、库表、契约均无变化。
2026-10-20 09:22:16 +08:00

81 lines
3.9 KiB
Bash
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.
# ═══════════════════════════════════════════════════════════
# 生产环境变量模板(prod)
#
# 用法:
# cp deploy/prod.env.example deploy/prod.env
# chmod 600 deploy/prod.env
# # 按下面命令生成四个密钥并填进去,再填 PG / REDIS / QINIU / WX
# set -a; . ./deploy/prod.env; set +a
# java -jar xt-server.jar --spring.profiles.active=prod
#
# 1Panel:把每一条粘到「应用 → 环境变量」,**值不要带引号**。
#
# ⚠️ deploy/prod.env 已 gitignore。不要把真值写回本文件。
# ⚠️ 2026-10 曾把 1Panel 的库/Redis 密码直接写进 application-prod.yml
# 并提交。那些值应视为已泄露:要么轮换,要么确认仓库只有可信的人能看。
# ═══════════════════════════════════════════════════════════
# ── PostgreSQL ────────────────────────────────────────────
# 1Panel 里通常就是容器名;换成你的实例地址
PG_HOST=
PG_PORT=5432
PG_DB=
PG_USER=
PG_PASSWORD=
# ── Redis ─────────────────────────────────────────────────
REDIS_HOST=
REDIS_PORT=6379
REDIS_PASSWORD=
# ── 四个密钥(必填,ProdEnvCheck 缺一个就拒绝启动)─────────
#
# XT_JWT_SECRET openssl rand -base64 64 | tr -d '\n'
# XT_AES_KEY openssl rand -base64 32 | tr -d '\n'
# XT_HMAC_KEY openssl rand -base64 48 | tr -d '\n'
# XT_RSA_PRIVATE_KEY openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out prod-rsa.pem
# openssl pkcs8 -topk8 -nocrypt -in prod-rsa.pem -outform DER | base64 -w0
#
# ⚠️ XT_AES_KEY 一旦用来加密过证件号就不能直接换(旧密文解不开且不报错)。
XT_JWT_SECRET=
XT_AES_KEY=
XT_HMAC_KEY=
XT_RSA_PRIVATE_KEY=
# ── 对象存储(生产必须 qiniu)──────────────────────────────
XT_STORAGE_PROVIDER=qiniu
QINIU_ACCESS_KEY=
QINIU_SECRET_KEY=
QINIU_BUCKET=
QINIU_DOMAIN=
QINIU_REGION=auto
# 启动时真的走一遍 写入→存在→读回→删除;密钥/空间配错会当场暴露
XT_STORAGE_SELF_CHECK=true
# false = 只保留压缩后的规范件(默认)
XT_STORAGE_KEEP_RAW=false
# ── 微信:小程序 ──────────────────────────────────────────
WX_MP_APP_ID=
WX_MP_APP_SECRET=
WX_MP_PUBLIC_BASE_URL=
WX_MP_ENV_VERSION=release
# ── 微信:公众号网页授权(H5)─────────────────────────────
# 回调与页面都必须是 https 正式域名,且与 H5 站点同源
WX_H5_APP_ID=
WX_H5_APP_SECRET=
WX_H5_CALLBACK=
WX_H5_BASE_URL=
# ── 其他 ─────────────────────────────────────────────────
XT_LOG_DIR=/var/log/xt
# 按域名区分单位时才打开
XT_TENANT_DOMAIN_ENABLED=false
XT_TENANT_DOMAIN_BASE=
# CORS 白名单(逗号分隔,Spring allowedOriginPatterns 语义)。
# ⚠️ **本站自己的地址也必须列上**:浏览器给同源的 POST 也带 Origin,
# 不在名单里 → 登录/上传一律 403「Invalid CORS request」(2026-10-20 生产事故)。
# PC 前端在 https://admin.shenxue.jxit.com,就是下面这行的默认值
# (application-prod.yml 里已经写了同样的默认,这里只是让它可运维覆盖)。
XT_CORS_ALLOWED_ORIGINS=https://shenxue.jxit.com,https://admin.shenxue.jxit.com,https://*.shenxue.jxit.com