

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 適用於 Java 的 DynamoDB 加密用戶端的範例程式碼
<a name="java-examples"></a>

**注意**  
我們的用戶端加密程式庫已[重新命名為 AWS 資料庫加密 SDK](DDBEC-rename.md)。下列主題提供有關適用於 Java 的 DynamoDB 加密用戶端 1.*x*-2.*x* 版和適用於 Python 的 DynamoDB 加密用戶端 1.*x*-3.*x* 版的資訊。如需詳細資訊，請參閱[AWS 資料庫加密 SDK for DynamoDB 版本支援](legacy-dynamodb-encryption-client.md#legacy-support)。

下列範例示範如何使用適用於 Java 的 DynamoDB 加密用戶端來保護應用程式中的 DynamoDB 資料表項目。您可以在 GitHub 上 [aws-dynamodb-encryption-java](https://github.com/aws/aws-dynamodb-encryption-java/) 儲存庫[的範例](https://github.com/aws/aws-dynamodb-encryption-java/tree/master/examples)目錄中找到更多範例 （並自行提供）。

**Topics**
+ [使用 DynamoDBEncryptor](#java-example-ddb-encryptor)
+ [使用 DynamoDBMapper](#java-example-dynamodb-mapper)

## 使用 DynamoDBEncryptor
<a name="java-example-ddb-encryptor"></a>

這個範例說明如何使用較低層級的 [DynamoDBEncryptor](https://aws.github.io/aws-dynamodb-encryption-java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/DynamoDBEncryptor.html) 搭配[直接 KMS 提供者](direct-kms-provider.md)。Direct 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：建立直接 KMS 提供者  
建立具有指定區域的 AWS KMS 用戶端執行個體。然後，使用用戶端執行個體，以您偏好的 建立直接 KMS 提供者的執行個體 AWS KMS key。  
此範例使用 Amazon Resource Name (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：建立 DynamoDBEncryptor  
使用直接 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);
```

## 使用 DynamoDBMapper
<a name="java-example-dynamodb-mapper"></a>

下列範例示範如何搭配 [Direct KMS 提供者](direct-kms-provider.md)使用 DynamoDB 映射器協助程式類別。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`，而且可以使用直接 KMS 提供者搭配較低層級的 `DynamoDBEncryptor`。

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

步驟 1：建立直接 KMS 提供者  
建立具有指定區域的 AWS KMS 用戶端執行個體。然後，使用用戶端執行個體，以您偏好的 建立直接 KMS 提供者的執行個體 AWS KMS key。  
此範例使用 Amazon Resource Name (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 加密程式和 DynamoDBMapper  
使用您在上一個步驟中建立的直接 KMS 提供者來建立 [DynamoDB 加密程式](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`) 都將進行加密並簽署。例外狀況是使用 DynamoDB Encryption Client 定義的 `@DoNotEncrypt`（僅簽署） 或 `@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);
```