我有一个Spring Boot应用程序,其中在src/main/resources目录中有多个.properties文件,我通过代码使用如下所示的内容:

@PropertySource(value = "classpath:properties/myfunctional.properties”)

目前,我能够使用它实现我的工作,因为它是一个简单的功能.

但问题是,将所有这.properties个文件保存在src/main/resources个文件中并不是一个好主意,原因如下:

  • .properties个文件将成为构建的一部分,并打包成.jar个文件.
  • 我想通过属性在代码库中存储像apikeytoken这样的敏感信息不是一种好的做法.

因此,我对此有几个问题:

  • 如何将我的.properties个文件全部移至外部服务器以及移至何处?
  • 如何在部署期间推出属性更改,因为这些值将根据环境(如devteststage和amp;prod)而有所不同?

我try 过的技术很少,有Spring Boot ConfigGit Secret Variable等等.但我还是不确定这些技术有多安全.

因此,我正在寻找一个涵盖更广泛方面的答案.

推荐答案

您可以通过Spring Cloud Config ServerClient.达到您的要求

请参考本文档here.


Github Approach:

循序渐进的过程,其中Githubrepo将作为包含机密/敏感数据的所有外部属性文件的来源.

  1. 我已经在我的Githubrepo上创建并托管了我所有的secrets-{env}.properties个文件,用于测试和演示.

enter image description here

secrets-dev.properties:

secrets.api-key=<dev-api-key>
secrets.token=<dev-token>

secrets-stage.properties:

secrets.api-key=<stage-api-key>
secrets.token=<stage-token>

secrets-test.properties:

secrets.api-key=<test-api-key>
secrets.token=<test-token>

secrets-prod.properties:

secrets.api-key=<prod-api-key>
secrets.token=<prod-token>
  1. 您必须创建和设置Spring Boot Cloud Configer服务器(充当external server),它将负责连接到Github外部存储库,并为客户端提供必要的方式来访问基于环境的属性文件.

项目 struct :

enter image description here

-pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.4</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>sb-externalize-config-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>sb-externalize-config-server</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2022.0.4</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

application.properties:个个

spring.cloud.config.server.git.uri=https://github.com/anishb266/secrets-repo
server.port=8081

Key points to be noted:

  • 您必须设置为spring.cloud.config.server.git.uri=https://github.com/anishb266/secrets-repo才能连接到该回购.

启动课程:

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

@SpringBootApplication
@EnableConfigServer
public class SbExternalizeConfigServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(SbExternalizeConfigServerApplication.class, args);
    }

}

您必须使用@EnableConfigServer才能使其成为外部配置服务器.

现在,我将在端口8081上运行外部配置服务器.

Output:个个个

访问其中一个属性,即secrets-test.properties,如下所示:

http://localhost:8081/{application}/{env} 

application - secrets
env - test

enter image description here

Config Server Log:

enter image description here

  1. 您必须创建和设置Spring bootstrap 云配置客户端,该客户端将连接到配置服务器并根据环境获取属性值.

项目 struct :

enter image description here

-pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>sb-externalize-config-client</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>sb-externalize-config-client</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2022.0.4</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

application.properties:个个

spring.config.import=optional:configserver:http://localhost:8081
server.port=8080
spring.application.name=secrets
spring.profiles.active=test

Key points to be noted here:

  • 为了查找配置服务器,您已经将spring.application.name与应用程序名称(这里是secrets)设置在-{env}.properties之前.否则,它就不会起作用了.基本上,它试图通过name of the application查找属性文件.默认情况下,该名称仅为application.因此,默认情况下,它将try 查找application-{env}.properties.

  • 对于测试,我保留spring.profiles.active=test,这样客户端将try 通过配置服务器从secrets-test.properties获取属性.

  • 您已将此设置为spring.config.import=optional:configserver:http://localhost:8081以连接到外部服务器.

SecretsProperties:

package com.example;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("secrets")
public class SecretsProperties {

    private String apiKey;

    private String token;

    public SecretsProperties(String apiKey, String token) {
        this.apiKey = apiKey;
        this.token = token;
    }

    @Override
    public String toString() {
        return "SecretsProperties [apiKey=" + apiKey + ", token=" + token + "]";
    }

    public String getApiKey() {
        return apiKey;
    }

    public void setApiKey(String apiKey) {
        this.apiKey = apiKey;
    }

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }

}

此类用于映射加载的属性.

启动类:

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

@SpringBootApplication
@EnableConfigurationProperties(SecretsProperties.class)
public class SbExternalizeConfigClientApplication {

    public static void main(String[] args) {
        SpringApplication.run(SbExternalizeConfigClientApplication.class, args);
    }

}

用于测试的TestController:

package com.example;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {

    private SecretsProperties properties;

    public TestController(SecretsProperties properties) {
        this.properties = properties;
    }

    @GetMapping("test-external-properties")
    public SecretsProperties testExternalProperties() {
        return properties;
    }

}

现在,我以8080的速度运行客户端,配置文件为test.

Client Log:

enter image description here

Output:个个个

enter image description here

提供外部配置服务器日志(log)的一部分,以证明客户端能够通过应用程序名称为secrets的配置服务器 Select 具有test配置文件的所需属性:

2023-10-16T18:04:48.433+05:30  INFO 79167 --- [nio-8081-exec-2] o.s.c.c.s.e.NativeEnvironmentRepository  : Adding property source: Config resource 'file [/var/folders/yq/m5hjv94j18586b1gzwzjg1tw0000gn/T/config-repo-5291131953887905898/secrets-test.properties]' via location 'file:/var/folders/yq/m5hjv94j18586b1gzwzjg1tw0000gn/T/config-repo-5291131953887905898/'

就这样.


HashiCorp Vault Approach:

如果你正在寻找一种更安全、更加密的保存财产的方式,那么 Select HashiCorp Vault.

Note:保险库充当保密的外部服务器.因此,您不需要从头开始创建外部服务器.

阅读Spring Boot文档here了解如何做到这一点.

来自文档:

保险库是一个秘密管理系统,允许您存储敏感信息 静态加密的数据.它是储存感光material 的理想 Select 配置详细信息,如密码、加密密钥、API密钥.

过程非常相似,但会有一些变化.

  • 首先下载适用于here的Electron 仓库.

  • 把它提取出来.将只有一个文件vault.sh.

  • 遵循安装过程here.

  • 出于演示的目的,我使用了这个命令->;./vault server --dev --dev-root-token-id="abc",其中我将一个示例令牌作为abc.请不要在比赛中这样跑.

  • 打开另一个控制台并执行此命令.

      export VAULT_TOKEN="abc"
      export VAULT_ADDR="http://127.0.0.1:8200"
    
  • 输入要存储的值.Format:

      ./vault kv put secret/{application-name}/{env} key=value
    
  • 将数据放入存储库的命令示例:

      ./vault kv put secret/secrets/test secrets.api-key=something secrets.token=something
    
      ./vault kv put secret/secrets/dev secrets.api-key=nothing secrets.token=nothing
    
  • 我将使用相同的现有客户端项目来演示.

Add this dependency in the -pom.xml:

<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-vault-config</artifactId>. 
</dependency>

您不再需要下面的依赖项:

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-config</artifactId>
    </dependency>

请把这个go 掉.

Pom.xml将如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>sb-externalize-config-client</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>sb-externalize-config-client</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2022.0.4</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-vault-config</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

使用以下属性设置application.properties:

spring.application.name=secrets
spring.cloud.vault.token=abc
spring.cloud.vault.scheme=http
spring.cloud.vault.kv.enabled=true
spring.cloud.vault.kv.default-context=
spring.config.import=vault://secret/${spring.application.name}/${spring.profiles.active}
spring.profiles.active=test

Points to be noted:

  • 默认情况下,Spring Cloud Starter保管库 Select 并附加/application作为应用程序名称,以从保管库中查找秘密.为了避免这种情况,我们需要添加spring.cloud.vault.kv.default-context=个属性.

TestControllerSecretsPropertiesSbExternalizeConfigClientApplication保持不变.

Output:个个个

我正在运行客户的test档案.

enter image description here

Note:这是我在使用Vault时展示的一个非常基本的方法.

Read docs for more info on how to do more advanced setup for Vault.

Java相关问答推荐

当列顺序更改时,Table View列列表的Change. wasPermanted()总是返回假

Mat. n_Delete()和Mat. n_release的区别

我想了解Java中的模块化.编译我的应用程序时,我有一个ResolutionException

从技术上讲,OPC UA客户端是否可以通过转发代理将请求通过 tunel 发送到OPC UA服务器?

Java inline Double条件和值解装箱崩溃

获取字符串中带空格的数字和Java中的字符

如何在运行时动态创建表(使用Java、JPA、SprringBoot)

JOOQ中的子查询使用的是默认方言,而不是配置的方言

未找到适用于响应类型[类java.io.InputStream]和内容类型[Text/CSV]的HttpMessageConverter

有效的公式或值列表必须少于或等于255个字符

Regex以查找不包含捕获组的行

Cordova Android Gradle内部版本组件不兼容

将关闭拍卖的TimerService

Android无法在Java代码中调用Kotlin代码,原因是在Companion中使用Kotlin枚举时

无法使用Open WebStart Java 8运行jnlp

Java 21内置http客户端固定运营商线程

当我将JTextField的getText函数与相等的String进行比较时;t返回true

Java泛型方法重载

元音变音字符:如何在 Java 中将Á<0x9c>转换为Ü?

单例模式中热切初始化和惰性初始化的区别