Spring Boot SSL API 消费
Springboot SLL API consume
我正在尝试使用来自第 3 方服务器的 API。第 3 方向我发送了一个名为 certificate.p12 的 SSL 证书,这是我用来进行握手的证书文件。我创建了一个带有 SSL 的自定义 RestTemplate,如下所示:
@Configuration
public class CustomRestTemplate {
private static final String PASSWORD = "fake_password";
private static final String RESOURCE_PATH = "keystore/certificate.p12";
private static final String KEY_TYPE = "PKCS12";
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) throws Exception {
char[] password = PASSWORD.toCharArray();
SSLContext sslContext = SSLContextBuilder
.create()
// .loadKeyMaterial(keyStore(RESOURCE_PATH, password), password)
.loadKeyMaterial(keyStore(getClass().getClassLoader().getResource(RESOURCE_PATH).getFile(), password), password)
.loadTrustMaterial(null, new TrustSelfSignedStrategy())
.build();
HttpClient client = HttpClients
.custom()
.setSSLContext(sslContext)
.build();
return builder
.requestFactory(() -> new HttpComponentsClientHttpRequestFactory(client))
.build();
}
private KeyStore keyStore(String file, char[] password) throws Exception {
KeyStore keyStore = KeyStore.getInstance(KEY_TYPE);
File key = ResourceUtils.getFile(file);
try (InputStream in = new FileInputStream(key)) {
keyStore.load(in, password);
}
return keyStore;
}
}
然后我使用以下代码调用端点:
@Component
@Service
public class TransactionService implements TransactionInterface {
@Autowired
private CustomRestTemplate restTemplate = new CustomRestTemplate();
private static final String BASE_URL = "https://41.x.x.x:xxxx/";
@Override
public List<Transaction> getUnsentTransactions(int connectionId) throws Exception {
HttpEntity<?> httpEntity = new HttpEntity<>(null, new HttpHeaders());
ResponseEntity<Transaction[]> resp = restTemplate
.restTemplate(new RestTemplateBuilder())
.exchange(BASE_URL + "path/end_point/" + connectionId, HttpMethod.GET, httpEntity, Transaction[].class);
return Arrays.asList(resp.getBody());
}
}
我在尝试使用 api 时得到以下堆栈跟踪:
org.springframework.web.client.ResourceAccessException: I/O error on GET request for \"https://41.x.x.x:xxxx/path/endpoint/parameters\": Certificate for <41.x.x.x> doesn't match any of the subject alternative names: [some_name_here, some_name_here];
我对 TLS 或 SSL 证书没有太多经验。我现在真的被困住了,希望能在这里得到一些帮助。第 3 方为我提供了一个测试站点,我可以在其中测试端点,在将 certificate.p12 文件导入我的浏览器后,我可以使用他们的测试站点到达端点,但我的 Springboot 应用程序仍然无法到达端点。
我需要将证书复制到特定文件夹吗?这似乎不是这种情况,因为如果我更改路径或文件名,我会得到一个 FileNotFoundException,如果我为 certificate.p12 文件输入错误的密码,我会得到一个密码不正确的错误。我尝试使用 Postman 对其进行测试,但 Postman returns 与我的 Web 应用程序具有相同的堆栈跟踪。
看了上面的信息,我是不是漏掉了什么?密钥库不是在运行时创建的吗?我是否需要将证书绑定到 JVM 或我的传出请求?
如有任何帮助,我们将不胜感激。
谢谢
您似乎正在尝试连接到证书中没有有效名称的服务器。例如,如果您要连接到 "whosebug.com",证书需要 "subject" 或 "subject alternative names" 字段中的域。
即使是测试站点也应该有有效的证书,但如果不可能(因为它是第三方站点,您不能自己更改),您可以使用 this question[= 禁用验证11=]
当然,这应该只是为了测试。
我正在尝试使用来自第 3 方服务器的 API。第 3 方向我发送了一个名为 certificate.p12 的 SSL 证书,这是我用来进行握手的证书文件。我创建了一个带有 SSL 的自定义 RestTemplate,如下所示:
@Configuration
public class CustomRestTemplate {
private static final String PASSWORD = "fake_password";
private static final String RESOURCE_PATH = "keystore/certificate.p12";
private static final String KEY_TYPE = "PKCS12";
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) throws Exception {
char[] password = PASSWORD.toCharArray();
SSLContext sslContext = SSLContextBuilder
.create()
// .loadKeyMaterial(keyStore(RESOURCE_PATH, password), password)
.loadKeyMaterial(keyStore(getClass().getClassLoader().getResource(RESOURCE_PATH).getFile(), password), password)
.loadTrustMaterial(null, new TrustSelfSignedStrategy())
.build();
HttpClient client = HttpClients
.custom()
.setSSLContext(sslContext)
.build();
return builder
.requestFactory(() -> new HttpComponentsClientHttpRequestFactory(client))
.build();
}
private KeyStore keyStore(String file, char[] password) throws Exception {
KeyStore keyStore = KeyStore.getInstance(KEY_TYPE);
File key = ResourceUtils.getFile(file);
try (InputStream in = new FileInputStream(key)) {
keyStore.load(in, password);
}
return keyStore;
}
}
然后我使用以下代码调用端点:
@Component
@Service
public class TransactionService implements TransactionInterface {
@Autowired
private CustomRestTemplate restTemplate = new CustomRestTemplate();
private static final String BASE_URL = "https://41.x.x.x:xxxx/";
@Override
public List<Transaction> getUnsentTransactions(int connectionId) throws Exception {
HttpEntity<?> httpEntity = new HttpEntity<>(null, new HttpHeaders());
ResponseEntity<Transaction[]> resp = restTemplate
.restTemplate(new RestTemplateBuilder())
.exchange(BASE_URL + "path/end_point/" + connectionId, HttpMethod.GET, httpEntity, Transaction[].class);
return Arrays.asList(resp.getBody());
}
}
我在尝试使用 api 时得到以下堆栈跟踪:
org.springframework.web.client.ResourceAccessException: I/O error on GET request for \"https://41.x.x.x:xxxx/path/endpoint/parameters\": Certificate for <41.x.x.x> doesn't match any of the subject alternative names: [some_name_here, some_name_here];
我对 TLS 或 SSL 证书没有太多经验。我现在真的被困住了,希望能在这里得到一些帮助。第 3 方为我提供了一个测试站点,我可以在其中测试端点,在将 certificate.p12 文件导入我的浏览器后,我可以使用他们的测试站点到达端点,但我的 Springboot 应用程序仍然无法到达端点。
我需要将证书复制到特定文件夹吗?这似乎不是这种情况,因为如果我更改路径或文件名,我会得到一个 FileNotFoundException,如果我为 certificate.p12 文件输入错误的密码,我会得到一个密码不正确的错误。我尝试使用 Postman 对其进行测试,但 Postman returns 与我的 Web 应用程序具有相同的堆栈跟踪。
看了上面的信息,我是不是漏掉了什么?密钥库不是在运行时创建的吗?我是否需要将证书绑定到 JVM 或我的传出请求?
如有任何帮助,我们将不胜感激。
谢谢
您似乎正在尝试连接到证书中没有有效名称的服务器。例如,如果您要连接到 "whosebug.com",证书需要 "subject" 或 "subject alternative names" 字段中的域。
即使是测试站点也应该有有效的证书,但如果不可能(因为它是第三方站点,您不能自己更改),您可以使用 this question[= 禁用验证11=]
当然,这应该只是为了测试。