

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 适用于 Java 的 DynamoDB 加密客户端的示例代码
<a name="java-examples"></a>

**注意**  
我们的客户端加密库已[重命名为 AWS 数据库加密 SDK](DDBEC-rename.md)。以下主题提供有关适用于 Java 的 DynamoDB 加密客户端版本 1.*x*—2.*x* 以及适用于 Python 的 DynamoDB 加密客户端版本 1.*x*—3.*x* 的信息。有关更多信息，请参阅[适用于 DynamoDB 的AWS 数据库加密 SDK 版本支持](legacy-dynamodb-encryption-client.md#legacy-support)。

以下示例为您演示如何使用适用于 Java 的 DynamoDB 加密客户端来保护应用程序中的 DynamoDB 表项目。你可以在上[aws-dynamodb-encryption-java](https://github.com/aws/aws-dynamodb-encryption-java/)存储库的示例目录中找到更多[示例](https://github.com/aws/aws-dynamodb-encryption-java/tree/master/examples)（并贡献自己的示例） GitHub。

**Topics**
+ [使用发电机 DBEncryptor](#java-example-ddb-encryptor)
+ [使用发电机 DBMapper](#java-example-dynamodb-mapper)

## 使用发电机 DBEncryptor
<a name="java-example-ddb-encryptor"></a>

此示例说明如何将较低级别的 [Dynamo DBEncryptor](https://aws.github.io/aws-dynamodb-encryption-java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/DynamoDBEncryptor.html) 与 Di [rect KMS](direct-kms-provider.md) 提供程序配合使用。直接 KMS 提供商在您指定的 [AWS KMS key](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#master_keys)in AWS Key Management Service (AWS KMS) 下生成并保护其加密材料。

您可以将任何兼容的[加密材料提供程序](DDBEC-legacy-concepts.md#concept-material-provider) (CMP) 与一起使用`DynamoDBEncryptor`，也可以将直接 KMS 提供程序与`DynamoDBMapper`和[AttributeEncryptor](java-using.md#attribute-encryptor)一起使用。

**查看完整的代码示例**：[AwsKmsEncryptedItem.java](https://github.com/aws/aws-dynamodb-encryption-java/blob/master/examples/src/main/java/com/amazonaws/examples/AwsKmsEncryptedItem.java)

步骤 1：创建 Direct KMS 提供程序  
创建指定区域的 AWS KMS 客户端实例。然后，使用客户端实例借助您的首选 AWS KMS key创建 Direct KMS 提供程序的实例。  
此示例使用 Amazon 资源名称 (ARN) 来标识 AWS KMS key，但您可以使用[任何有效的密钥](https://docs.aws.amazon.com/kms/latest/developerguide/viewing-keys.html#find-cmk-id-arn)标识符。  

```
final String keyArn = "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab";
final String region = "us-west-2";
      
final AWSKMS kms = AWSKMSClientBuilder.standard().withRegion(region).build();
final DirectKmsMaterialProvider cmp = new DirectKmsMaterialProvider(kms, keyArn);
```

步骤 2：创建项目  
此示例定义了`record` HashMap 表示示例表项的。  

```
final String partitionKeyName = "partition_attribute";
final String sortKeyName = "sort_attribute";

final Map<String, AttributeValue> record = new HashMap<>();
record.put(partitionKeyName, new AttributeValue().withS("value1"));
record.put(sortKeyName, new AttributeValue().withN("55"));
record.put("example", new AttributeValue().withS("data"));
record.put("numbers", new AttributeValue().withN("99"));
record.put("binary", new AttributeValue().withB(ByteBuffer.wrap(new byte[]{0x00, 0x01, 0x02})));
record.put("test", new AttributeValue().withS("test-value"));
```

步骤 3：创建发电机 DBEncryptor  
使用 Direct KMS 提供程序创建 `DynamoDBEncryptor` 的实例。  

```
final DynamoDBEncryptor encryptor = DynamoDBEncryptor.getInstance(cmp);
```

步骤 4：创建 DynamoDB 加密上下文  
[DynamoDB 加密上下文](concepts.md#encryption-context)包含有关表结构以及其如何加密和签名的信息。如果使用的是 `DynamoDBMapper`，则 `AttributeEncryptor` 会为您创建加密上下文。  

```
final String tableName = "testTable";

final EncryptionContext encryptionContext = new EncryptionContext.Builder()
    .withTableName(tableName)
    .withHashKeyName(partitionKeyName)
    .withRangeKeyName(sortKeyName)
    .build();
```

步骤 5：创建属性操作对象  
[属性操作](DDBEC-legacy-concepts.md#legacy-attribute-actions)确定已加密并签名的项目属性、仅签名的属性以及未加密或签名的属性。  
在 Java 中，要指定属性操作，需要创建属性名称和`EncryptionFlags`值对。 HashMap   
例如，以下 Java 代码创建了一个`actions` HashMap 对`record`项目中的所有属性进行加密和签名，但分区键和排序密钥属性（已签名但未加密）以及未签名或加密的`test`属性除外。  

```
final EnumSet<EncryptionFlags> signOnly = EnumSet.of(EncryptionFlags.SIGN);
final EnumSet<EncryptionFlags> encryptAndSign = EnumSet.of(EncryptionFlags.ENCRYPT, EncryptionFlags.SIGN);
final Map<String, Set<EncryptionFlags>> actions = new HashMap<>();

for (final String attributeName : record.keySet()) {
  switch (attributeName) {
    case partitionKeyName: // fall through to the next case
    case sortKeyName:
      // Partition and sort keys must not be encrypted, but should be signed
      actions.put(attributeName, signOnly);
      break;
    case "test":
      // Neither encrypted nor signed
      break;
    default:
      // Encrypt and sign all other attributes
      actions.put(attributeName, encryptAndSign);
      break;
  }
}
```

步骤 6：加密并签名项目  
要加密并签名项目，请对 `encryptRecord` 的实例调用 `DynamoDBEncryptor` 方法。指定表项目 (`record`)、属性操作 (`actions`) 和加密上下文 (`encryptionContext`)。  

```
final Map<String, AttributeValue> encrypted_record = encryptor.encryptRecord(record, actions, encryptionContext);
```

步骤 7：将项目放入 DynamoDB 表中  
最后，将已加密且签名的项目放入 DynamoDB 表中。  

```
final AmazonDynamoDB ddb = AmazonDynamoDBClientBuilder.defaultClient();
ddb.putItem(tableName, encrypted_record);
```

## 使用发电机 DBMapper
<a name="java-example-dynamodb-mapper"></a>

以下示例为您演示如何结合使用 DynamoDB Mapper 帮助程序类与 [Direct KMS 提供程序](direct-kms-provider.md)。Direct KMS 提供程序借助您指定的 AWS Key Management Service （AWS KMS）中的 [AWS KMS key](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#master_keys) 生成并保护其加密材料。

您可以结合使用任何兼容的[加密材料提供程序](DDBEC-legacy-concepts.md#concept-material-provider) (CMP) 与 `DynamoDBMapper`，也可以结合使用 Direct KMS 提供程序与低级别 `DynamoDBEncryptor`。

**查看完整的代码示例**：[AwsKmsEncryptedObject.java](https://github.com/aws/aws-dynamodb-encryption-java/blob/master/examples/src/main/java/com/amazonaws/examples/AwsKmsEncryptedObject.java)

步骤 1：创建 Direct KMS 提供程序  
创建指定区域的 AWS KMS 客户端实例。然后，使用客户端实例借助您的首选 AWS KMS key创建 Direct KMS 提供程序的实例。  
此示例使用 Amazon 资源名称 (ARN) 来标识 AWS KMS key，但您可以使用[任何有效的密钥](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id)标识符。  

```
final String keyArn = "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab";
final String region = "us-west-2";
      
final AWSKMS kms = AWSKMSClientBuilder.standard().withRegion(region).build();
final DirectKmsMaterialProvider cmp = new DirectKmsMaterialProvider(kms, keyArn);
```

第 2 步：创建 DynamoDB 加密器和 Dynamo DBMapper  
使用您在上一步中创建的 Direct KMS 提供程序创建 [DynamoDB Encryptor](java-using.md#attribute-encryptor) 的实例。您需要实例化低级别 DynamoDB Encryptor 才能使用 DynamoDB Mapper。  
接着，创建 DynamoDB 数据库的实例和映射器配置，然后使用它们创建 DynamoDB Mapper 的实例。  
当使用 `DynamoDBMapper` 添加或编辑已签名（或已加密并签名）项目时，将其配置为[使用保存行为](java-using.md#save-behavior)（如包含所有属性的 `PUT`），如以下示例所示。否则，您可能无法解密您的数据。

```
final DynamoDBEncryptor encryptor = DynamoDBEncryptor.getInstance(cmp)
final AmazonDynamoDB ddb = AmazonDynamoDBClientBuilder.standard().withRegion(region).build();

DynamoDBMapperConfig mapperConfig = DynamoDBMapperConfig.builder().withSaveBehavior(SaveBehavior.PUT).build();
DynamoDBMapper mapper = new DynamoDBMapper(ddb, mapperConfig, new AttributeEncryptor(encryptor));
```

步骤 3：定义您的 DynamoDB 表  
接下来，定义您的 DynamoDB 表。使用注释指定[属性操作](java-using.md#attribute-actions-java)。此示例将创建一个 DynamoDB 表、`ExampleTable`，以及一个表示表项目的 `DataPoJo` 类。  
在此示例表中，将为主键属性签名，但不进行加密。这适用于使用 `@DynamoDBHashKey` 进行注释的 `partition_attribute` 以及使用 `@DynamoDBRangeKey` 进行注释的 `sort_attribute`。  
将为使用 `@DynamoDBAttribute` 进行注释的属性（如 `some numbers`）加密并签名。使用 `@DoNotEncrypt`（仅签名）或 DynamoDB 加密客户端定义的 `@DoNotTouch`（不进行加密或签名）加密注释的属性则例外。例如，由于 `leave me` 属性具有 `@DoNotTouch` 注释，因此不会为其加密或签名。  

```
@DynamoDBTable(tableName = "ExampleTable")
public static final class DataPoJo {
  private String partitionAttribute;
  private int sortAttribute;
  private String example;
  private long someNumbers;
  private byte[] someBinary;
  private String leaveMe;

  @DynamoDBHashKey(attributeName = "partition_attribute")
  public String getPartitionAttribute() {
    return partitionAttribute;
  }

  public void setPartitionAttribute(String partitionAttribute) {
    this.partitionAttribute = partitionAttribute;
  }

  @DynamoDBRangeKey(attributeName = "sort_attribute")
  public int getSortAttribute() {
    return sortAttribute;
  }

  public void setSortAttribute(int sortAttribute) {
    this.sortAttribute = sortAttribute;
  }

  @DynamoDBAttribute(attributeName = "example")
  public String getExample() {
    return example;
  }

  public void setExample(String example) {
    this.example = example;
  }

  @DynamoDBAttribute(attributeName = "some numbers")
  public long getSomeNumbers() {
    return someNumbers;
  }

  public void setSomeNumbers(long someNumbers) {
    this.someNumbers = someNumbers;
  }

  @DynamoDBAttribute(attributeName = "and some binary")
  public byte[] getSomeBinary() {
    return someBinary;
  }

  public void setSomeBinary(byte[] someBinary) {
    this.someBinary = someBinary;
  }

  @DynamoDBAttribute(attributeName = "leave me")
  @DoNotTouch
  public String getLeaveMe() {
    return leaveMe;
  }

  public void setLeaveMe(String leaveMe) {
    this.leaveMe = leaveMe;
  }

  @Override
  public String toString() {
    return "DataPoJo [partitionAttribute=" + partitionAttribute + ", sortAttribute="
        + sortAttribute + ", example=" + example + ", someNumbers=" + someNumbers
        + ", someBinary=" + Arrays.toString(someBinary) + ", leaveMe=" + leaveMe + "]";
  }
}
```

步骤 4：加密并保存表项目  
现在，当您创建一个表项目并使用 DynamoDB Mapper 保存它时，会在将此项目添加到表之前自动对其进行加密和签名。  
此示例定义一个名为 `record` 的表项目。在将此表项目保存到表中之前，将基于 `DataPoJo` 类中的注释为其属性加密和签名。在此示例中，将为 `PartitionAttribute`、`SortAttribute` 和 `LeaveMe` 之外的所有属性加密和签名。仅为 `PartitionAttribute` 和 `SortAttributes` 进行签名。不会为 `LeaveMe` 属性加密或签名。  
要为 `record` 项目加密并签名，然后将其添加到 `ExampleTable`，请调用 `DynamoDBMapper` 类的 `save` 方法。由于您的 DynamoDB Mapper 配置为使用 `PUT` 保存行为，因此项目将替换具有相同主键的任何项目，而不是更新这些项目。这将确保签名匹配，并且您可以在从表中获取项目时为其解密。  

```
DataPoJo record = new DataPoJo();
record.setPartitionAttribute("is this");
record.setSortAttribute(55);
record.setExample("data");
record.setSomeNumbers(99);
record.setSomeBinary(new byte[]{0x00, 0x01, 0x02});
record.setLeaveMe("alone");

mapper.save(record);
```