diff --git a/.gitignore b/.gitignore index bd8c463..ff077d3 100644 --- a/.gitignore +++ b/.gitignore @@ -19,7 +19,19 @@ data/uploads/* # 部署用的真实环境变量(含密钥),只提交 .env.example .env +*.secrets.env dump.rdb # 看门狗飞书告警 Webhook,只存在于部署机 deploy/feishu-webhook.txt + +# SSL 证书与私钥(.crt/.cer/.pem/.key/.p12/.jks)—— 部署机本地文件,禁止入库 +*.crt +*.cer +*.pem +*.key +*.p12 +*.jks + +# 部署用 nginx 配置目录(挂载卷的本地配置,随环境而异) +nginx/ diff --git a/docker-compose.yml b/docker-compose.yml index 624c462..f70ff90 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -80,7 +80,7 @@ services: REDIS_PORT: ${REDIS_PORT:-6379} # CORS:公网入口 nginx 把 SSL 跑在 80 端口上(腾讯云安全组只放 80), # 浏览器 fetch 带 Origin 时端口不匹配会被 Spring CORS 拒(必须精确字符串匹配)。 - CORS_ALLOWED_ORIGINS: "https://api.frostgiant.vip:80,https://api.frostgiant.vip,http://api.frostgiant.vip,https://39.162.50.99:8081,http://localhost:3005,http://127.0.0.1:3005" + CORS_ALLOWED_ORIGINS: "https://api.frostgiant.vip:80,https://api.frostgiant.vip,http://api.frostgiant.vip,https://39.162.50.99:8081,http://localhost:3005,http://127.0.0.1:3005,http://39.162.50.99:3007,http://192.168.31.250:3007" ports: - "8081:8081" volumes: diff --git a/fruitshorts-admin-api/src/main/resources/application.yml b/fruitshorts-admin-api/src/main/resources/application.yml index 2930a0c..a34920a 100644 --- a/fruitshorts-admin-api/src/main/resources/application.yml +++ b/fruitshorts-admin-api/src/main/resources/application.yml @@ -57,14 +57,14 @@ fruitshorts: public-prefix: /files chunk-size: 5242880 max-file-size: 2147483648 - signature-secret: ${MEDIA_SIGNATURE_SECRET:fruitshorts-media-dev-secret-change-me-in-production-32b} + signature-secret: ${MEDIA_SIGNATURE_SECRET:} signature-required: ${MEDIA_SIGNATURE_REQUIRED:false} signature-ttl-minutes: 15 jwt: - # 双密钥都要外置:只配 admin 而漏配 app,生产会静默用 dev 默认值(prod fail-fast 会拦住) - admin-secret: ${JWT_ADMIN_SECRET:fruitshorts-admin-dev-secret-change-me-in-production-32b} + # ⚠️ 所有环境必须注入 JWT_ADMIN_SECRET / JWT_APP_SECRET,不设任何代码级默认值 + admin-secret: ${JWT_ADMIN_SECRET:} admin-ttl-hours: 12 - app-secret: ${JWT_APP_SECRET:fruitshorts-app-dev-secret-change-me-in-production-32bytes} + app-secret: ${JWT_APP_SECRET:} app-access-ttl-minutes: 120 app-refresh-ttl-days: 30 cors: diff --git a/fruitshorts-app-api/src/main/resources/application.yml b/fruitshorts-app-api/src/main/resources/application.yml index 7e088c3..aa219cf 100644 --- a/fruitshorts-app-api/src/main/resources/application.yml +++ b/fruitshorts-app-api/src/main/resources/application.yml @@ -99,15 +99,15 @@ fruitshorts: chunk-size: 5242880 max-file-size: 2147483648 # 播放地址签名:生产必开(docs/12-上线检查清单),prod profile 里强制为 true - signature-secret: ${MEDIA_SIGNATURE_SECRET:fruitshorts-media-dev-secret-change-me-in-production-32b} + signature-secret: ${MEDIA_SIGNATURE_SECRET:} signature-required: ${MEDIA_SIGNATURE_REQUIRED:false} signature-ttl-minutes: 15 jwt: # 双密钥:管理端与客户端物理隔离,token 不能互换(AGENTS.md 强制约束 2) - # 注意 app-secret 以前没写在这里,一直用代码里的 dev 默认值 —— 生产必须注入 JWT_APP_SECRET - admin-secret: ${JWT_ADMIN_SECRET:fruitshorts-admin-dev-secret-change-me-in-production-32b} + # ⚠️ 所有环境必须注入 JWT_ADMIN_SECRET / JWT_APP_SECRET,不设任何代码级默认值 + admin-secret: ${JWT_ADMIN_SECRET:} admin-ttl-hours: 12 - app-secret: ${JWT_APP_SECRET:fruitshorts-app-dev-secret-change-me-in-production-32bytes} + app-secret: ${JWT_APP_SECRET:} app-access-ttl-minutes: 120 app-refresh-ttl-days: 30 cors: diff --git a/fruitshorts-framework/src/main/java/com/fruitshorts/framework/security/JwtProperties.java b/fruitshorts-framework/src/main/java/com/fruitshorts/framework/security/JwtProperties.java index 0b7d788..9f88ac9 100644 --- a/fruitshorts-framework/src/main/java/com/fruitshorts/framework/security/JwtProperties.java +++ b/fruitshorts-framework/src/main/java/com/fruitshorts/framework/security/JwtProperties.java @@ -11,17 +11,17 @@ import org.springframework.stereotype.Component; @ConfigurationProperties(prefix = "fruitshorts.jwt") public class JwtProperties { - /** 管理端签名密钥,长度必须 >= 32 字节。生产环境通过环境变量注入。 */ - private String adminSecret = "fruitshorts-admin-dev-secret-change-me-in-production-32b"; + /** 管理端签名密钥,长度必须 >= 32 字节。**所有环境必须通过环境变量注入,不设任何默认值。** */ + private String adminSecret = ""; /** 管理端 token 有效期(小时)。 */ private int adminTtlHours = 12; /** * 客户端签名密钥。与管理端物理隔离:管理端 token 拿到客户端接口上无法通过验签, - * 反之亦然。生产环境必须通过环境变量注入,不要沿用默认值。 + * 反之亦然。**所有环境必须通过环境变量注入,不设任何默认值。** */ - private String appSecret = "fruitshorts-app-dev-secret-change-me-in-production-32bytes"; + private String appSecret = ""; /** 客户端 access token 有效期(分钟)。 */ private int appAccessTtlMinutes = 120; diff --git a/fruitshorts-module-media/src/main/java/com/fruitshorts/media/config/MediaProperties.java b/fruitshorts-module-media/src/main/java/com/fruitshorts/media/config/MediaProperties.java index 8bc8883..d8c24f0 100644 --- a/fruitshorts-module-media/src/main/java/com/fruitshorts/media/config/MediaProperties.java +++ b/fruitshorts-module-media/src/main/java/com/fruitshorts/media/config/MediaProperties.java @@ -23,8 +23,8 @@ public class MediaProperties { /** 单个文件大小上限(字节),默认 2GB。 */ private long maxFileSize = 2L * 1024 * 1024 * 1024; - /** 播放地址签名密钥(不少于 32 字节)。生产环境必须用环境变量注入。 */ - private String signatureSecret = "fruitshorts-media-dev-secret-change-me-in-production-32b"; + /** 播放地址签名密钥(不少于 32 字节)。**所有环境必须通过环境变量注入,不设任何默认值。** */ + private String signatureSecret = ""; /** 播放签名有效期(分钟)。默认 15 分钟,足够播完一集且不易被长期复用。 */ private int signatureTtlMinutes = 15;