知識庫 / Spring / Spring Cloud RSS 訂閱

Spring Cloud 配置快速入門

Spring Cloud,Spring Security
HongKong
5
02:48 PM · Dec 06 ,2025

1. 概述

Spring Cloud Config 是 Spring 的客户端/服務器架構,用於在多個應用程序和環境中存儲和提供分佈式配置。

此配置存儲庫理想情況下應在 Git 版本控制下進行版本管理,並且可以在運行時通過應用程序進行修改。它非常適合與 Spring 應用程序一起使用,並結合了諸如 EnvironmentPropertySource 或 @Value 等構造,但也可在任何使用任何編程語言的任何環境中進行使用。

在本教程中,我們將重點介紹如何設置一個基於 Git 的配置服務器,並在一個簡單的 REST 應用程序服務器中使用它,並設置一個安全的環境,包括加密的屬性值。

2. 項目設置與依賴項

首先,我們將創建兩個新的 Maven 項目。 服務器項目依賴於 spring-cloud-config-server 模塊,以及 spring-boot-starter-securityspring-boot-starter-web 啓動包:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

然而,對於該客户端項目,我們只需要 spring-cloud-starter-config 模塊以及 spring-boot-starter-web 模塊:

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

3. 配置服務器實現

應用程序的主要部分是一個配置類,更具體地説是一個 @SpringBootApplication,它通過 @EnableConfigServer 註解從所有必需的設置中拉取所有內容。

@SpringBootApplication
@EnableConfigServer
public class ConfigServer {
    
    public static void main(String[] arguments) {
        SpringApplication.run(ConfigServer.class, arguments);
    }
}

現在我們需要配置服務器監聽的 端口,以及一個 Git URL,該 URL 提供我們的版本控制配置內容。 後者可以使用諸如 httpssh 或本地文件系統上的簡單 文件 等協議。

提示: 如果我們計劃使用指向同一配置倉庫的多個配置服務器實例,則可以配置服務器將我們的倉庫克隆到本地臨時文件夾。 但請注意,帶有兩步驗證的私有倉庫處理起來比較困難。 在這種情況下,在本地文件系統中克隆並使用副本會更容易。

此外,還有一些用於配置 repository-url 的佔位符變量和搜索模式可用;但這些超出了本文的範圍。 如果您想了解更多信息,官方文檔是一個不錯的起點。

我們還需要為 Basic-Authentication 在我們的 application.properties 中設置用户名和密碼,以避免在每次應用程序重啓時自動生成密碼:

server.port=8888
spring.cloud.config.server.git.uri=ssh://localhost/config-repo
spring.cloud.config.server.git.clone-on-start=true
spring.security.user.name=root
spring.security.user.password=s3cr3t

4. 使用 Git 倉庫作為配置存儲

為了完成我們的服務器,我們需要在配置的 URL 下初始化一個 Git 倉庫,創建一些新的屬性文件,並用一些值填充它們。

配置文件的名稱類似於標準的 Spring application.properties,但 대신 ‘application’ 這個詞,使用配置的名稱,例如屬性 ‘spring.application.name’ 的值,後跟一個連字符和活動配置文件。例如:

$> git init
$> echo 'user.role=Developer' > config-client-development.properties
$> echo 'user.role=User'      > config-client-production.properties
$> git add .
$> git commit -m 'Initial config-client properties'

故障排除: 如果我們遇到與 ssh 相關的身份驗證問題,我們可以檢查我們的 ssh 服務器上的 ~/.ssh/known_hosts~/.ssh/authorized_keys

5. 查詢配置

現在我們能夠啓動服務器。服務器提供的、基於 Git 的配置 API 可以通過以下路徑進行查詢:

/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties

`{label} 佔位符指代一個 Git 分支,{application} 指代客户端應用程序名稱,{profile} 則指代客户端當前活躍的應用程序配置文件。

因此,我們可以通過以下方式獲取我們計劃運行在 master 分支下,使用開發配置的客户端配置:`

$> curl http://root:s3cr3t@localhost:8888/config-client/development/master

6. 客户端實現

接下來,我們處理客户端。這將是一個非常簡單的客户端應用程序,它包含一個 REST 控制器和一個 GET 方法。

為了從服務器獲取配置,必須將配置放置在 application.properties 文件中。Spring Boot 2.4 引入了一種使用 spring.config.import 屬性加載配置數據的全新方式,現在它是綁定到 Config Server 的默認方式:

@SpringBootApplication
@RestController
public class ConfigClient {
    
    @Value("${user.role}")
    private String role;

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

    @GetMapping(
      value = "/whoami/{username}",  
      produces = MediaType.TEXT_PLAIN_VALUE)
    public String whoami(@PathVariable("username") String username) {
        return String.format("Hello! 
          You're %s and you'll become a(n) %s...\n", username, role);
    }
}

除了應用程序名稱,我們還在 application.properties 中添加了當前激活的配置文件和連接詳細信息:

spring.application.name=config-client
spring.profiles.active=development
spring.config.import=optional:configserver:http://root:s3cr3t@localhost:8888

這將連接到 Config Server,地址為 http://localhost:8888,同時使用 HTTP 基本身份驗證來發起連接。 此外,我們還可以通過分別設置 spring.cloud.config.usernamespring.cloud.config.password 屬性來設置用户名和密碼。

在某些情況下,如果客户端無法連接到 Config Server,我們可能希望中止服務的啓動。 如果這是期望的行為,可以移除 optional: 前綴,使客户端在拋出異常時立即停止。

為了測試配置是否已成功從服務器接收,以及 角色值 是否注入到控制器的方法中,我們只需在客户端啓動後使用 curl 進行測試:

$> curl http://localhost:8080/whoami/Mr_Pink

如果響應如下,我們的 Spring Cloud Config Server 和其客户端目前正常工作:

Hello! You're Mr_Pink and you'll become a(n) Developer...

7. 加密與解密

要求: 為了使用強大的加密密鑰與 Spring 的加密解密功能一起使用,我們需要安裝 Java 密碼擴展 (JCE) 無限強度管轄範圍文件 到我們的 JVM 中。 這些文件可以從 Oracle 下載。 要安裝,請按照下載包中提供的説明進行操作。 某些 Linux 發行版也通過其包管理器提供可安裝的軟件包。

由於配置服務器支持屬性值的加密解密,我們可以使用公共存儲庫作為存儲敏感數據(如用户名和密碼)的地方。 加密後的值以字符串 {cipher} 開頭,可以通過 REST 調用路徑 /encrypt 生成,如果服務器配置使用對稱密鑰或密鑰對。

還有一個解密端點可用。 兩個端點都接受一個包含應用程序名稱和當前配置文件佔位符的路徑: /*/{name}/{profile}。 這對於按客户端控制密碼學特別有用。 但是,在它們有用的前提下,我們必須配置一個加密密鑰,我們將會在下一部分中完成。

提示: 如果我們使用 curl 調用加密/解密 API,最好使用 –data-urlencode 選項(而不是 –data/-d),或者顯式設置 ‘Content-Type’ 標題為 text/plain。 這確保了正確處理加密值中的特殊字符,如 ‘+’。

如果通過客户端獲取的值無法自動解密,則其 密鑰 將被重命名為與名稱相同,並以“invalid”開頭。 這可以防止使用加密值作為密碼。

提示: 當設置包含 YAML 文件的存儲庫時,必須用單引號將加密且帶有前綴的值括起來。 但是,這不適用於 Properties。

7.1. 跨站請求偽造 (CSRF)

Spring Security 默認情況下會為發送到我們應用程序的所有請求啓用跨站請求偽造 (CSRF) 保護。

因此,為了能夠使用 /encrypt/decrypt 端點,我們應該為它們禁用 CSRF:

@Configuration
public class SecurityConfiguration {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.csrf(csrf -> csrf.ignoringRequestMatchers(
           "/encrypt/**", "/decrypt/**"
        ))

        //...
    }
}

7.2. 密鑰管理

默認情況下,配置服務器能夠以對稱或非對稱方式加密屬性值。

要使用對稱密碼學,只需將 ‘encrypt.key’ 屬性設置為我們選擇的密鑰。

此外,我們還可以通過傳遞環境變量 ENCRYPT_KEY

要使用非對稱密碼學,可以將 ‘encrypt.key’ 設置為 PEM 編碼的字符串值或配置 keystore

由於我們需要一個高度安全的演示服務器環境,因此我們將選擇後者,包括生成一個新的密鑰存儲,其中包含一個 RSA 密鑰對,首先使用 Java keytool

$> keytool -genkeypair -alias config-server-key \
       -keyalg RSA -keysize 4096 -sigalg SHA512withRSA \
       -dname 'CN=Config Server,OU=Spring Cloud,O=Baeldung' \
       -keypass my-k34-s3cr3t -keystore config-server.jks \
       -storepass my-s70r3-s3cr3t

然後我們將創建的 keystore 添加到服務器的 application.properties 文件中,並重新運行它:

encrypt.keyStore.location=classpath:/config-server.jks
encrypt.keyStore.password=my-s70r3-s3cr3t
encrypt.keyStore.alias=config-server-key
encrypt.keyStore.secret=my-k34-s3cr3t

接下來,我們將查詢加密端點,並將響應作為值添加到我們存儲庫中的配置中:

$> export PASSWORD=$(curl -X POST --data-urlencode d3v3L \
       http://root:s3cr3t@localhost:8888/encrypt)
$> echo "user.password={cipher}$PASSWORD" >> config-client-development.properties
$> git commit -am 'Added encrypted password'
$> curl -X POST http://root:s3cr3t@localhost:8888/refresh

為了測試我們的設置是否正確工作,我們將修改 ConfigClient 類並重啓我們的客户端:

@SpringBootApplication
@RestController
public class ConfigClient {

    ...
    
    @Value("${user.password}")
    private String password;

    ...
    public String whoami(@PathVariable("username") String username) {
        return String.format("Hello! 
          You're %s and you'll become a(n) %s, " +
          "but only if your password is '%s'!\n", 
          username, role, password);
    }
}

最後,我們對客户端執行一個查詢,以驗證我們的配置值是否正確解密。

$> curl http://localhost:8080/whoami/Mr_Pink
Hello! You're Mr_Pink and you'll become a(n) Developer, \
  but only if your password is 'd3v3L'!

7.3. 使用多個密鑰

如果需要為加密和解密使用多個密鑰,例如為每個已部署的應用程序指定一個專用密鑰,則可以在 <em{cipher}</em> 鍵前加上以<em{name:value} 的形式的前綴,並與 BASE64 編碼的屬性值之間添加一個前綴。

配置服務器可以“幾乎”無縫地理解像 <em{secret:my-crypto-secret}</em> 或<em{key:my-key-alias} 這樣的前綴。 後者選項需要在我們的 `application.properties 中配置一個密鑰存儲(keystore)。 密鑰存儲會搜索與密鑰別名匹配的密鑰。 例如:

user.password={cipher}{secret:my-499-s3cr3t}AgAMirj1DkQC0WjRv...
user.password={cipher}{key:config-client-key}AgAMirj1DkQC0WjRv...

對於沒有 keystore 的場景,我們需要實現一個 @Bean,類型為 TextEncryptorLocator,它負責查找併為每個密鑰返回一個 TextEncryptor 對象。

7.4. 本地解密屬性服務

如果我們要禁用服務器端加密並本地處理屬性值的解密,可以在服務器的 <em >application.properties</em > 文件中添加以下內容:

spring.cloud.config.server.encrypt.enabled=false

此外,我們還可以刪除所有“encrypt.*”屬性以禁用 REST 端點。

8. 結論

現在,我們能夠創建一個配置服務器,從 Git 倉庫提供一組配置文件給客户端應用程序。 此外,我們還可以做一些其他事情。

例如:

  • YAMLProperties 格式提供配置,而不是 JSON,同時解析佔位符。 這在非 Spring 環境中使用時非常有用,此時配置並不能直接映射到 PropertySource
  • 提供純文本配置文件,並可選地解析佔位符。 例如,這可以用於提供環境相關的日誌配置。
  • 將配置服務器嵌入到應用程序中,其中它從 Git 倉庫配置自身,而不是作為獨立應用程序運行,為客户端服務。 因此,我們必須設置一些屬性,或者必須刪除 @EnableConfigServer 註解,這取決於用例。
  • 使配置服務器在 Spring Netflix Eureka 服務發現中可用,並啓用客户端中的自動服務器發現。 這在服務器沒有固定位置或移動位置時變得重要。
user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.