如何在使用Spring SslBundle的SpringBoot RestClient中禁用SSL验证(信任不安全主机)
嘿,我完全懂你的需求——你已经靠RestClient+SslBundle成功发了客户端证书给第三方,但现在想跳过对他们服务器证书的验证,还不想退回到老掉牙的RestTemplate。之前你试着删掉truststore配置,结果发现根本不等于用InsecureTrustManagerFactory,对吧?确实,Spring不会自动帮你切换到不安全的信任管理器,得咱们手动配置才行。
下面给你两种可行的方案,全都是基于SslBundle的,完全不用碰RestTemplate:
方案一:基于现有SslBundle构建自定义「不安全」Bundle(推荐)
这个思路很简单:保留你已经配置好的keystore(毕竟还要给第三方发客户端证书),但把信任管理器换成「信任所有证书」的实现,同时跳过主机名验证。
步骤1:保留配置文件的keystore配置
你的配置文件不用改,就用你之前修改后的版本(只留keystore,删掉truststore):
spring: ssl: bundle: jks: mybundle: keystore: location: C:\\ssl\\keystore.p12 password: 123 type: PKCS12 reload-on-update: true
步骤2:创建自定义的不安全SslBundle Bean
我们基于原有的mybundle,构建一个新的SslBundle,替换掉信任管理器和主机名验证器:
import org.springframework.boot.ssl.SslBundle; import org.springframework.boot.ssl.SslBundles; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.net.ssl.InsecureTrustManagerFactory; import javax.net.ssl.NoopHostnameVerifier; @Configuration public class InsecureSslConfig { @Bean public SslBundle insecureSslBundle(SslBundles sslBundles) { // 获取我们配置的只包含keystore的原始bundle SslBundle originalKeystoreBundle = sslBundles.getBundle("mybundle"); // 构建新的不安全Bundle:保留keystore,替换信任和主机名验证逻辑 return SslBundle.builder() .from(originalKeystoreBundle) // 信任所有证书(对应InsecureTrustManagerFactory.INSTANCE) .trustManagerFactory(() -> InsecureTrustManagerFactory.INSTANCE) // 跳过主机名验证(信任任何主机名) .hostnameVerifier(NoopHostnameVerifier.INSTANCE) .build(); } }
步骤3:在RestClient中使用这个不安全的Bundle
修改你的RestClient Bean,用咱们自定义的insecureSslBundle:
@Bean public RestClient restClient(RestClient.Builder builder, SslBundle insecureSslBundle) { return builder.baseUrl("https://the-secure-api.com/api") .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE) .apply(RestClientSsl.fromBundle(insecureSslBundle)) .build(); }
方案二:直接在RestClient Bean中内联构建不安全Bundle(更简洁)
如果不想单独写一个SslBundle Bean,也可以直接在RestClient的配置里内联完成,效果完全一样:
@Bean public RestClient restClient(RestClient.Builder builder, SslBundles sslBundles) { // 获取原始keystore bundle SslBundle originalBundle = sslBundles.getBundle("mybundle"); // 内联构建不安全Bundle SslBundle insecureBundle = SslBundle.builder() .from(originalBundle) .trustManagerFactory(() -> InsecureTrustManagerFactory.INSTANCE) .hostnameVerifier(NoopHostnameVerifier.INSTANCE) .build(); return builder.baseUrl("https://the-secure-api.com/api") .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE) .apply(RestClientSsl.fromBundle(insecureBundle)) .build(); }
关键说明&注意事项
为什么之前的方法没用?
当你只配置keystore而不配置truststore时,Spring会默认用系统的信任库(比如JDK的cacerts),而不是自动切换到不安全的信任管理器。所以必须显式指定InsecureTrustManagerFactory才行。Spring版本兼容性
- 如果你用Spring Boot 3.2+,可以用
SslTrustManagerFactories.insecure()代替() -> InsecureTrustManagerFactory.INSTANCE,用SslHostnameVerifiers.NONE代替NoopHostnameVerifier.INSTANCE——这俩是Spring封装的便捷方法,更贴合Spring的API风格。 - 3.1及以下版本就用上面代码里的
InsecureTrustManagerFactory和NoopHostnameVerifier就行。
- 如果你用Spring Boot 3.2+,可以用
安全警告!!!
这个配置绝对只能在测试/开发环境用!生产环境禁用SSL验证会让你的请求完全暴露在中间人攻击(MITM)的风险下,后果不堪设想。
内容来源于stack exchange

