ARTICLE · 1038764
【AI+DevOps实战-04】密码别入库_多环境凭据治理
大家好,我是质量架构师东哥,专注软件研发过程中的质量和效率改进。
讲清原理,打通实战,拒绝空谈欢迎关注。
本文承接 【AI+DevOps实战-03】别让AI裸奔_SDD锁住生成一致性,在上一篇中我们已经完成了一个“最简单的”健康检查接口开发,本篇我们讲解项目必备的多环境及账号密码如何管理。同时也响应 constitution 的"凭据治理"条款落地成三环境(dev/test/prod)配置文件体系。核心是两件事:配置怎么组织(双 profile + 环境自包含)和凭据怎么不入库(分层占位策略)。
一、问题背景
1.1 上游若依的原始配置
若依官方 ruoyi-admin/src/main/resources/ 默认长这样:
application.yml # 主配置:含 Redis、端口、token 等
application-druid.yml # 单一数据源(明文账号密码!)
问题:
单 profile:
spring.profiles.active: druid,没有 dev/test/prod 区分,生产测试共用一份配置。Redis 写在公共 yml:所有环境共用同一 Redis 地址,无法按环境切换。
明文凭据:
application-druid.yml里username: root / password: password明文入库。
1.2 二次开发要解决的矛盾
本项目要同步上游 + 独立部署三环境,配置必须满足:
三环境(dev/test/prod)各有独立的库、Redis、Flyway 开关。
凭据不能明文进 git(constitution 要求"库内 yml 保留示例值")。
本地开发要开箱即用(不能每次 clone 都先配一堆环境变量)。
上游
application.yml是上游文件,改动要最小化(便于 merge upstream)。
二、方案:双 profile + 环境自包含
2.1 双 profile 机制(业务配置 + 数据源分离)
Spring Boot 的 spring.profiles.active 支持逗号分隔多 profile。我们把业务配置和数据源拆成两条线,各自按环境命名:
application.yml # 主配置:真公共项(端口/上传/token/MyBatis 等)
application-{env}.yml # 业务差异:Redis + Flyway + 日志
application-druid-{env}.yml # 数据源:Druid 连接池 + 控制台
启动时用双 profile 激活对应环境:
dev,druid-dev | ||
test,druid-test | ||
prod,druid-prod |

为什么拆两条线? Druid 数据源配置很长(连接池参数 40+ 行),如果和业务配置混在一个文件,每环境都要复制一大坨。拆开后,
application-{env}.yml只管 Redis/Flyway/日志(环境差异项),application-druid-{env}.yml管数据源,职责清晰。
2.2 环境自包含法(对齐源项目规范)
关键决策:主 application.yml不放 Redis 和 Flyway——这两项是环境差异项(各环境 Redis 地址/密码、Flyway 开关都不同),由各 application-{env}.yml 各自完整配置。
主 application.yml 只放真正的跨环境公共项:
spring:
profiles:
# 本地默认激活开发环境(dev 业务配置 + druid-dev 数据源)
# 测试环境启动用 --spring.profiles.active=test,druid-test
# 生产环境启动用 --spring.profiles.active=prod,druid-prod
active: dev,druid-dev
# 注意:Redis 与 Flyway 为环境差异项(各环境地址/开关不同),
# 不放在本公共文件,由 application-{env}.yml 各自配置,对齐源项目规范
# ...端口、上传、token、MyBatis、xss 等真公共项...
各 application-{env}.yml自包含该环境的 Redis + Flyway:
# application-dev.yml
spring:
data:
redis:
host: 192.168.30.41
password: ${REDIS_PASSWORD:changeme}
flyway:
enabled:false# 开发频繁改 SQL,关掉
2.3 对比:骨架覆盖法 vs 环境自包含法
有两种组织多环境配置的思路,本项目选了后者:
| 自包含 | ||
环境自包含法的代价是连接池参数在三份 yml 里重复(审查也指出了),可用
spring.config.import共享 yml 去重,但当前复杂度可接受,先不自证。
三、凭据分层占位策略
3.1 constitution 的凭据条款
memory/constitution.md Security 段:
凭据不入库:数据源、Redis 等连接信息含真实密码时,禁止明文入库。采用
${ENV_VAR:默认值}占位。
关键区分:IP 非凭据,可保留明文;密码是凭据,必须环境变量化。
3.2 Spring Boot 占位语法 ${ENV_VAR:默认值}
password: ${DB_PASSWORD:changeme}
含义:优先读环境变量 DB_PASSWORD;未设则用冒号后的默认值 changeme。这样:
部署前
export DB_PASSWORD=真实密码→ 用真实值不设环境变量 → 用默认值(本地兜底 / 占位符)
3.3 三环境分层策略
不同环境对"默认值"的要求不同,故分层:
| dev | ${REDIS_PASSWORD:123456}) | |
| test | changeme | |
| prod | changeme |
# application-dev.yml(本地友好)
password: ${REDIS_PASSWORD:123456}# 默认真值,clone 即用
# application-test.yml(占位符)
password: ${REDIS_PASSWORD:changeme}# 必须 export 才能用
# application-prod.yml(占位符)
password: ${REDIS_PASSWORD:changeme}# 必须 export 才能用
dev 为什么保留真值? 这是宪法字面("库内 yml 保留示例值")与用户体验的权衡。dev 环境面向开发者本地,要求每次 clone 都先 export 一堆变量太痛苦;内网开发库密码泄露面可控。test/prod 面向共享环境/生产,凭据必须零入库。审查指出这与 constitution 字面有出入——属已知的设计决策权衡。
3.4 完整占位变量清单
部署 test/prod 前,运维必须 export 这些环境变量:
# 数据源
exportDB_USERNAME=数据库账号
exportDB_PASSWORD=数据库密码
# Redis
exportREDIS_PASSWORD=Redis密码
# Druid 监控控制台
exportDRUID_USERNAME=Druid控制台账号
exportDRUID_PASSWORD=Druid控制台密码
未设任一项,对应服务连接失败(changeme 不是有效凭据)。
3.5 本地覆盖:application-local.yml
若不想用 dev 默认值(比如连自己的本地库),可建 application-local.yml 覆盖,并加进 .gitignore(不入库):
# application-local.yml(加 .gitignore,不入库)
spring:
data:
redis:
password: 我的本地Redis密码
datasource:
druid:
master:
password: 我的本地库密码
启动加 local profile:--spring.profiles.active=local,dev,druid-dev(local 覆盖 dev)。
四、IP 处理:示例化
4.1 IP 是凭据吗
constitution 明确:IP 非凭据。内网 IP 暴露的风险远低于密码——知道了 IP 没有凭据也连不上。所以源项目规范里 IP 可保留明文。
五、文件清单与切换
5.1 最终配置文件结构
ruoyi-admin/src/main/resources/
├── application.yml # 主配置(真公共项,不含 Redis/Flyway,active: dev,druid-dev)
├── application-dev.yml # 开发:Redis(.41 真值) + Flyway 关 + debug 日志
├── application-druid-dev.yml # 开发数据源(.41/ai-devops,真值兜底)
├── application-test.yml # 测试:Redis(.130.41) + Flyway 开 + info 日志
├── application-druid-test.yml # 测试数据源(.130.41,changeme 占位)
├── application-prod.yml # 生产:Redis(.130.31) + Flyway 开 + info 日志
└── application-druid-prod.yml # 生产数据源(.130.30,changeme 占位)
上游若依原始
application-druid.yml(单数、明文)已删除,对齐源项目规范——本地默认走application-druid-dev.yml。
5.2 环境切换
后端:改启动参数或 ry.sh:
# 本地默认(不指定,用主 yml 的 active: dev,druid-dev)
java-jar ruoyi-admin.jar
# 测试
java-jar-Dspring.profiles.active=test,druid-test ruoyi-admin.jar
# 生产
java-jar-Dspring.profiles.active=prod,druid-prod ruoyi-admin.jar
前端:Vite 环境变量(.env.development/.staging/.production):
yarn dev # 开发(/dev-api → Vite proxy → localhost:8080)
yarn build:stage # 测试(/stage-api → Nginx)
yarn build:prod # 生产(/prod-api → Nginx 负载均衡)
5.3 确认当前环境
启动日志会打印 The following profiles are active: dev,druid-dev,一眼可见。
六、踩坑记录
6.1 Redis/Flyway 放公共 yml 的陷阱
最初把 Redis 和 Flyway 放主 application.yml(当"骨架默认值"),各 env 只覆盖差异。问题:
dev/test 的 Redis 同在
.41但 Flyway 开关不同(dev 关/test 开),用覆盖法要小心"覆盖了地址还是覆盖了开关"。Flyway 在 Spring Boot 4.1.0 移除了自动配置(详见 【AI+DevOps实战-05】Flyway终结数据库变更混乱),
spring.flyway.*没有框架自动绑定,放公共 yml 反而误导(以为改了就生效)。
改环境自包含后,看一个 application-{env}.yml 就懂该环境 Redis + Flyway 全貌,不再有"骨架/覆盖"的隐式依赖。
6.2 changeme 占位符的失败显式
test/prod 用 changeme 而非空字符串作默认值——是有意为之:未设环境变量时让连接失败,而不是静默用空密码连库(可能连上无密码的 Redis)。changeme 是无效凭据,连接会报错,运维能立刻发现没 export。
6.3 删 application-druid.yml 的遗漏
多 profile 重构时,最初只新建了 application-druid-{env}.yml,忘了删上游的 application-druid.yml——导致两份数据源配置并存。后补了一个 chore(admin): 删除上游明文 application-druid.yml 提交才对齐源项目规范。提醒:重构删除类操作要单独成提交,别和新增混在一起,容易漏。
七、与 constitution 的对应
${ENV_VAR:默认值} | |
八、延伸
constitution 凭据条款全文:
memory/constitution.mdSecurity 段多环境部署完整文档:
docs/deploy/多环境部署文档.md(含 Nginx、ry.sh、备份脚本)
下一篇 【AI+DevOps实战-05】Flyway让AI看懂数据库的版本化变更 聚焦 Flyway 在 Spring Boot 4.1 + 若依动态数据源下的手动配置——为什么 spring.flyway.* 不生效,怎么手动绑定主数据源。
如果你觉得这篇文章写的还不错,麻烦双击屏幕点个👍、点个❤️、点个转发,你的支持是我继续分享的动力!
关注公众号回复:ai-devops 获取本系列完整源码。