应使用 secrets-gradle-plugin 隔离 Nexus/Maven 仓库密钥,将凭证注入 BuildConfig 而非硬编码;CI 中须用平台原生密钥机制临时生成 secrets.properties 并严格清理,杜绝明文泄露风险。

别把 Nexus / Maven 仓库的账号密码写进 build.gradle 或 gradle.properties —— 它们极大概率会被提交到 Git,且在 CI 日志、IDE 缓存、团队共享环境里反复暴露。
为什么 gradle.properties 不是安全终点
很多人以为把密码从 build.gradle 搬到项目根目录下的 gradle.properties 就算“脱敏”了,其实不然:这个文件默认不被 .gitignore 覆盖;IDE(如 Android Studio)会自动加载它;CI 环境也默认读取它——只要它存在,就等于把密钥放在所有构建环节的必经之路上。
常见错误现象:
- CI 构建日志里明文打印出
Could not authenticate with repository: user=xxx, password=***(实际可能没打星号) - 新人 clone 项目后执行
./gradlew build失败,然后在群里问“MAVEN_USER密码是多少?” - 某次误操作把本地
gradle.properties提交到了公开仓库,搜索引擎一周内就能抓到
用 secrets-gradle-plugin 隔离构建时密钥注入
这个插件专为 Android/Java Gradle 项目设计,核心思路是:密钥不参与构建脚本解析,只在编译期注入 BuildConfig 或 resValue,且默认不打包进 APK。
实操要点:
- 在项目级
build.gradle的buildscript { dependencies { ... } }中添加插件依赖:classpath "com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.1" - 在模块级
build.gradle顶部用plugins { id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin' }启用 - 创建
secrets.properties(务必加进.gitignore),内容如:nexusUser=admin和nexusPassword=real_password_here - 在
android { defaultConfig { ... } }里用buildConfigField "String", "NEXUS_USER", "\"${nexusUser}\""注入,后续代码中直接用BuildConfig.NEXUS_USER
注意:该插件不会帮你配置仓库地址本身——maven { url "https://nexus.example.com/repository/maven/" } 可以写死,但认证必须走插件注入,否则 Gradle 会在 resolve 阶段报 401 Unauthorized。
CI/CD 中真正安全的密码传递方式
本地开发用 secrets.properties,CI 环境必须切换成平台原生密钥机制,否则等于把密码从一个明文文件搬到另一个明文环境变量里。
不同平台做法差异明显:
- GitHub Actions:用
secrets.NEXUS_PASSWORD+env:块注入,再通过echo "${{ secrets.NEXUS_PASSWORD }}" > secrets.properties临时生成文件(执行完立即rm) - GitLab CI:定义
variables:下的NEXUS_PASSWORD,勾选 “Mask variable”(但注意:仅对日志生效,仍需配合before_script写入临时文件) - Jenkins:推荐用 Credentials Binding 插件,绑定为文件类型凭据,路径固定为
secrets.properties,无需硬编码路径
关键判断点:任何把密码塞进 environment 或 export 的写法,如果没做日志屏蔽或文件清理,都只是障眼法。真正的隔离,是让密码只存在于进程内存和临时文件中,且生命周期严格限定在单次构建内。
为什么不用 keystore.properties 那套方案?
keystore.properties 是为签名密钥设计的,它的加载逻辑写死在 signingConfigs 里,不适用于仓库认证这种需要在 repositories { } 块中动态提供凭证的场景。Gradle 的 maven { credentials { ... } } 不支持引用外部属性文件的值——它只接受字面量或闭包计算结果,而闭包里又不能安全读取本地文件(会破坏可重现构建)。所以必须用插件在构建前期完成变量注入,再由 Gradle 原生机制消费。
最容易被忽略的一点:Nexus 仓库密码一旦泄露,攻击者不仅能下载私有依赖,还能上传伪造构件覆盖合法版本——权限比签名密钥更危险,因为它直接影响整个团队的供应链完整性。











