AWS 开发工具包提供了几种实现方式SdkHttpClient
,您可以使用这些实现方式与您的 Amazon 服务进行同步或异步交互。
例如,您可以使用ApacheHttpClient
该类。
所有这些 HTTP 客户端都是用 s 创建和配置Builder
的,ApacheHttpClient.Builder
对于ApacheHttpClient
.
ApacheHttpClient.Builder
提供允许您为客户端、远程对等点或相互身份验证配置安全 HTTP 连接的方法。
如果客户端必须经过身份验证,则必须提供必须用于该目的的证书和私钥,对应于调用的--cert
和--key
参数。curl
通常,此证书和私钥存储在一个受密码保护的文件KeyStore
中,通常采用 PKCS#12 格式(a.p12
或.pfx
文件)。
可以通过ApacheHttpClient.Builder
两种方式访问此信息。
首先,通过设置一系列System
属性:
import static software.amazon.awssdk.utils.JavaSystemSetting.SSL_KEY_STORE;
import static software.amazon.awssdk.utils.JavaSystemSetting.SSL_KEY_STORE_PASSWORD;
import static software.amazon.awssdk.utils.JavaSystemSetting.SSL_KEY_STORE_TYPE;
//...
Path clientKeyStore = Paths.get(...);
System.setProperty(SSL_KEY_STORE.property(), clientKeyStore.toAbsolutePath().toString());
System.setProperty(SSL_KEY_STORE_TYPE.property(), "pkcs12");
System.setProperty(SSL_KEY_STORE_PASSWORD.property(), "password");
注意:static
导入只是标准JSSE属性javax.net.ssl.keyStore
、javax.net.ssl.keyStorePassword
和javax.net.ssl.keyStoreType
.
其次,通过提供方法的TlsKeyManagersProvider
实现。例如:tlsKeyManagersProvider
ApacheHttpClient.Builder
Path clientKeyStore = ...
TlsKeyManagersProvider keyManagersProvider = FileStoreTlsKeyManagersProvider.create(clientKeyStore, "pkcs12", "password");
事实上,在底层,上面提到System
的基于属性的配置是由SystemPropertyTlsKeyManagersProvider
另一个TlsKeyManagersProvider
实现使用的。
如果您需要对服务器进行身份验证,您还有两种选择。
首先,再次通过设置几个System
属性:
Path serverKeyStore = Paths.get(...);
System.setProperty("javax.net.ssl.trustStore", serverKeyStore.toAbsolutePath().toString());
System.setProperty("javax.net.ssl.trustStorePassword", "password");
System.setProperty("javax.net.ssl.trustStoreType", "jks");
如您所见,为简单起见,这次我们使用不同类型的KeyStore
, jks
。KeyStore
您可以使用以下内容从您的 AWS 服务器证书 PEM 文件(与--cacert
您的curl
命令关联的文件)构建这样一个:
Path pemPath = ...;
try(final InputStream is = Files.newInputStream(pemPath) {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) certificateFactory.generateCertificate(is);
String alias = cert.getSubjectX500Principal().getName();
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
keyStore.setCertificateEntry(alias, cert);
}
在相互身份验证的情况下,虽然您可以重复使用相同的KeyStore
,但最佳做法是维护两个,一个使用客户端私钥和证书,另一个使用您将信任的服务器证书(信任库)。
或者,您也可以通过定义TrustManager
需要使用的 s 来配置服务器端身份验证。
对于这个任务,ApacheHttpClient.Builder
提供了方法tlsTrustManagersProvider
。此方法需要实现TlsTrustManagersProvider接口。
该接口定义了一个方法,它返回必须用于检查 SSL 通信中的远程对等trustManagers
点的 s 数组。TrustManager
不幸的是,AWS SDK 不提供此接口的实现,您需要自己实现(如果您需要更多信息,请告诉我)。
初始化和配置后,您可以分别使用或方法将 thisSdkHttpClient
或其SdkHttpClient.Builder
, 提供给自定义服务客户端,例如。IotClient
httpClient
httpClientBuilder
如果您只需要像使用curl
命令一样测试 TLS 连接,您可以尝试以下操作:
Path clientKeyStore = Paths.get(...);
System.setProperty("javax.net.ssl.keyStore", clientKeyStore.toAbsolutePath().toString());
System.setProperty("javax.net.ssl.keyStoreType", "pkcs12");
System.setProperty("javax.net.ssl.keyStorePassword", "password");
Path serverKeyStore = Paths.get(...);
System.setProperty("javax.net.ssl.trustStore", serverKeyStore.toAbsolutePath().toString());
System.setProperty("javax.net.ssl.trustStorePassword", "password");
System.setProperty("javax.net.ssl.trustStoreType", "jks");
SdkHttpClient client = ApacheHttpClient.builder().build();
SdkHttpRequest httpRequest = SdkHttpFullRequest.builder()
.method(SdkHttpMethod.GET)
.uri(new URI("https://<prefix>.credentials.iot.us-west-2.amazonaws.com/role-aliases/MyAlias/credentials"))
.putHeader("x-amzn-iot-thingname", "myThingName")
.build();
HttpExecuteRequest request = HttpExecuteRequest.builder()
.request(httpRequest)
.build();
HttpExecuteResponse response = client.prepareRequest(request).call();
请在 AWS Java 开发工具包中查看此测试,它也会有所帮助。
最后,您还可以在项目中使用异步 HTTP 客户端。在这些客户端中配置安全 HTTP 通信的方式与上述段落中描述的方式非常相似。
您可以在AWS Java SDK v2 GitHub 存储库中找到所有这些资源。
您可以在项目中导入整个 SDK(我假设您使用的是 Maven):
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>aws-sdk-java</artifactId>
<version>2.15.7</version>
</dependency>
虽然,为了测试 Apache HTTP 客户端,我认为以下依赖项将是唯一必要的:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>apache-client</artifactId>
<version>2.15.7</version>
</dependency>
尽管我试图将答案集中在 AWS SDK 提供的代码上,但据我所知,为了获得这些临时凭证,也可以使用任何允许安全连接到 AWS 的机制,例如 Apache HttpClient,例如在您的示例中,OkHttp 等。
这些临时凭证可用于签署任何 AWS 请求并根据假定的 IAM 角色在 AWS 服务上执行操作。例如,按照您指出的博客中的示例,您可以在 DynamoDB 表中插入一个项目:
AwsSessionCredentials credentials = AwsSessionCredentials.create(
"the_returned_access_key_id",
"the_returned_secret_key_id",
"the_returned_session_token"
);
DynamoDbClient ddb = DynamoDbClient.builder()
.region(Region.US_EAST_1)
.credentialsProvider(StaticCredentialsProvider.create(credentials))
.build();
HashMap<String,AttributeValue> itemValues = new HashMap<String,AttributeValue>();
itemValues.put("serial_number", AttributeValue.builder().s("123456789").build());
itemValues.put("timestamp", AttributeValue.builder().s("2017-11-20T06:00:00.000Z").build());
itemValues.put("current_temp", AttributeValue.builder().n("65").build());
itemValues.put("target_temp", AttributeValue.builder().n("70").build());
itemValues.put("humidity", AttributeValue.builder().n("45").build());
PutItemRequest request = PutItemRequest.builder()
.tableName("MyHomeThermostat")
.item(itemValues)
.build();
try {
ddb.putItem(request);
} catch (ResourceNotFoundException e) {
//...
} catch (DynamoDbException e) {
//...
}
关于您在上面评论中如何更新获得的令牌的问题,我必须承认我无法给您答案。
在我看来,恐怕上述调用返回的临时凭证无法刷新,至少 AWS SDK 没有为此提供任何机制:这个凭证提供程序是为物联网设计的一个非常具体的用例,如您引用的博客和官方 AWS 文档。
AWS 开发工具包提供了不同AWSCredentialsProvider
的支持令牌更新的 s,例如StsAssumeRoleCredentialsProvider
orStsGetSessionTokenCredentialsProvider
等,但没有针对此用例的特定提供商。
如果有任何帮助,您可以查看基类的源代码StsCredentialsProvider
,特别是其构造函数中与设置CachedSupplier
和相关内容相关的代码。