使用带有pem证书的RestTemplate

6

我有带有私钥和服务器证书的pem证书。我可以使用curl执行它,一切正常。

curl -O -k --cert-type pem --cert mypem.pem url

但是我想在Java中使用它,最好使用Spring的RestTemplate。

2个回答

12

对于使用 pem 证书与 RestTemplate 的知识比较分散。

必须执行以下步骤:

  1. 使用 keytool 或 portecle 将服务器证书添加到 trustStore 中。如果要使用自定义 trusttore,请使用此 脚本

  2. 接下来,将 ssl 配置到 RestTemplate 中。可以按照以下方法执行:

  3. @Configuration
    public class SSLConfiguration {
    
    @Value("${certificate.name}")
    private String name;
    
    @Bean(name = "sslContext")
    public SSLContext sslContext() throws Exception {
      Security.addProvider(new BouncyCastleProvider());
      return SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).useTLS().build();
    }
    
    @Bean(name = "sslSocketFactory")
    public SSLSocketFactory sslSocketFactory() throws Exception {
    
      return new ConnectionFactoryCreator(name, sslContext()).getSocketFactory();
    
    }
    
    @Bean(name = "httpClient")
    public HttpClient httpClient() throws Exception {
      return HttpClientBuilder.create().setSslcontext(sslContext())
            .setSSLSocketFactory(new SSLConnectionSocketFactory(sslSocketFactory(), new AllowAllHostnameVerifier()))
            .build();
    }
    
    @Bean
    public ClientHttpRequestFactory httpClientRequestFactory() throws Exception {
      return new HttpComponentsClientHttpRequestFactory(httpClient());
    }
    
    @Bean
    public RestTemplate restTemplate() throws Exception {
      return new RestTemplate(httpClientRequestFactory());
     }
    
    }
    

并且

public class ConnectionFactoryCreator {

   private final String pemName;

   private final SSLContext context;

   public ConnectionFactoryCreator(String pemName, SSLContext context) {
      this.pemName = pemName;
      this.context = context;
   }

   public SSLSocketFactory getSocketFactory() throws Exception {

      InputStream resourceAsStream = getClass().getResourceAsStream(pemName);
  byte[] certAndKey = ByteStreams.toByteArray(resourceAsStream);

  byte[] certBytes = parseDERFromPEM(certAndKey, "-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----");
  byte[] keyBytes = parseDERFromPEM(certAndKey, "-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----");

  X509Certificate cert = generateCertificateFromDER(certBytes);

  PrivateKey key = generatePrivateKeyFromDER(keyBytes);

  KeyStore keystore = KeyStore.getInstance("JKS");
  keystore.load(null);
  keystore.setCertificateEntry("cert-alias", cert);
  keystore.setKeyEntry("key-alias", key, "changeit".toCharArray(), new Certificate[] { cert });

  KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
  kmf.init(keystore, "changeit".toCharArray());

  KeyManager[] km = kmf.getKeyManagers();

  context.init(km, null, null);

  return context.getSocketFactory();
   }

   private byte[] parseDERFromPEM(byte[] pem, String beginDelimiter, String endDelimiter) {
  String data = new String(pem);
  String[] tokens = data.split(beginDelimiter);
  tokens = tokens[1].split(endDelimiter);
  return DatatypeConverter.parseBase64Binary(tokens[0]);
   }

   private PrivateKey generatePrivateKeyFromDER(byte[] keyBytes)
     throws InvalidKeySpecException, NoSuchAlgorithmException {
  PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);

  KeyFactory factory = KeyFactory.getInstance("RSA");

  return factory.generatePrivate(spec);
   }

   private X509Certificate generateCertificateFromDER(byte[] certBytes) throws CertificateException {
  CertificateFactory factory = CertificateFactory.getInstance("X.509");

  return (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(certBytes));
 }

最后,您可以使用 inject restTemplate 来连接到 URL。


看起来很有用,但是你能展示一下如何使用你的代码和RestTemplate吗?谢谢 - BSeitkazin
@BSeitkazin,使用它就像平常一样。 - vanduc1102

1

在导入时我遇到了以下问题:keytool 错误: java.lang.Exception: 输入不是 X.509 证书。 - marok

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接