【问题标题】:How to use p12 client certificate with spring feign client如何将 p12 客户端证书与 spring feign 客户端一起使用
【发布时间】:2020-01-23 08:35:31
【问题描述】:

我有一个调用远程服务的 Spring Boot 应用程序。

这个远程 Web 服务为我提供了一个 p12 文件,该文件应该对我的应用程序进行身份验证。

如何配置我的 feign 客户端以使用 p12 证书?


我已经尝试设置这些属性:

-Djavax.net.ssl.keyStore=path_to_cert.p12 -Djavax.net.ssl.keyStorePassword=xxx -Djavax.net.ssl.keyStoreType=PKCS12

但它并没有改变任何东西,我仍然得到这个错误:

sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

【问题讨论】:

    标签: spring-boot client-certificates spring-cloud-feign


    【解决方案1】:

    我终于可以通过大量的盲目试验和错误来做到这一点。

    问题是,默认情况下,feign builder 使用 null SSLSocketFactory 构建 feign 客户端:

    org.springframework.cloud.openfeign.FeignClientsConfiguration#feignBuilder

    @Bean
    @Scope("prototype")
    @ConditionalOnMissingBean
    public Feign.Builder feignBuilder(Retryer retryer) {
        return Feign.builder().retryer(retryer);
    }
    

    feign.Feign.Builder

      public static class Builder {
        // ...
        private Client client = new Client.Default(null, null);
    

    所以,我必须在 @Configuration 中定义这个 bean:

    @Bean
    @Profile({"prod", "docker"})
    public Feign.Builder feignBuilder() {
        return Feign.builder()
            .retryer(Retryer.NEVER_RETRY)
            .client(new Client.Default(getSSLSocketFactory(), null));
    

    用这个方法:(不记得出处)

    SSLSocketFactory getSSLSocketFactory() {
        char[] allPassword = keyStorePassword.toCharArray();
        SSLContext sslContext = null;
        try {
            sslContext = SSLContextBuilder
                .create()
                .setKeyStoreType(keyStoreType)
                .loadKeyMaterial(ResourceUtils.getFile(keyStore), allPassword, allPassword)
                .build();
        } catch (Exception e) { /* *** */ }
        return sslContext.getSocketFactory();
    }
    

    现在,它对我有用,我通过 feign 客户端调用进行了调试,并且 sslSocketFactory 已正确传递给底层连接。

    【讨论】:

    • keyStorePassword、keyStoreType、keyStore 变量都是从哪里来的?
    • 一种直接的方法是将值存储在 application.properties/yml 中并将它们传递到使用 @ConfigurationProperties 注释的类的 keyStorePassword, keyStoreType, keyStore 字段中
    【解决方案2】:

    如果您希望在不使用 keytool 的情况下以编程方式实现上述效果,您可以执行以下操作:

    class CustomFeignConfiguration {
    
        private val log = Logger.getLogger(this.javaClass.name)
    
        @Value("\${client_p12_base64_encoded_string}")
        private val clientP12: String = ""
    
        @Value("\${client_p12_password}")
        private val clientP12Pass: String = ""
    
        @Bean
        fun feignClient(): Client {
            val sslSocketFactory= getSSLSocketFactory()
            log.info("CUSTOM FEIGN CLIENT CALLED")
            return Client.Default(sslSocketFactory, DefaultHostnameVerifier())
        }
    
        private fun getSSLSocketFactory(): SSLSocketFactory {
            val decoder = java.util.Base64.getDecoder()
            val p12 = decoder.decode(clientP12)
            val p12File = File("clientCer.p12")
            p12File.writeBytes(p12)
    
            try {
                val sslContext = SSLContexts
                    .custom()
                    .loadKeyMaterial(p12File, clientP12Pass.toCharArray(), clientP12Pass.toCharArray())
                    .build()
                return sslContext.socketFactory
            } catch (exception: Exception) {
                throw RuntimeException(exception)
            }
    
        }
    }
    

    使用配置的FeignClient接口必须专门加载这个

    @FeignClient(name = "client", configuration = [CustomFeignConfiguration::class], url = "\${url}")
    interface Client {
      ....
      ....
    }
    

    SSLContexts 库只能使用 p12 证书,我们必须将 PEM 格式的证书和密钥转换为 P12 格式。

    使用以下 SSL 命令从您的 PEM 证书和密钥创建 p12 证书:

    openssl pkcs12 -export -inkey domain.key -in domain.crt -out domain.p12
    

    请记录您在运行此命令后输入的密码。

    使用以下命令将此 p12 证书转换为 base64 字符串

    base64 domain.p12 > domain.p12.base64
    

    使用以下命令将此多行字符串转换为单行字符串:

    tr -d "\n\r" < domain.p12.base64 > domain.p12.base64.singleline
    

    使用此命令中的单行字符串和您之前在 application.properties 中记录的密码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-24
      • 2013-01-19
      • 1970-01-01
      • 1970-01-01
      • 2012-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多