注意:

使用 Shell 和 Java Code 以编程方式管理 Oracle Cloud Infrastructure REST API

简介

Oracle Cloud Infrastructure (OCI) 为客户提供云基础设施,帮助客户在云端托管关键任务应用。OCI 还为客户提供通过控制台或 API 访问 OCI 服务的方式。对于通过 API 进行连接,客户可以使用基于编程语言的 SDK,例如 Java、Python 或 Ruby。但是,在少数情况下,客户无法使用 SDK,也无法使用任何编程语言,而是希望通过 API 直接从工具、数据库或第三方应用程序连接,而这些应用程序无法安装 SDK。REST API 的使用非常方便。客户可以将 OCI 提供的 REST API 用于几乎所有服务,只需更新端点并进行授权和身份验证,即可直接在工具中使用这些 API。

如今,每个组织都希望在应用中利用 REST API 的强大功能,并为客户创建创新产品,而无需安装和管理任何 SDK。

在本教程中,我们将讨论并了解 OCI 如何帮助全球组织利用 OCI 的 REST API 的强大功能。在本教程中,我们将演示基于 shell 脚本和 Java 代码的 REST API 示例。

目标

先决条件

任务 1:设置 Oracle Cloud Infrastructure API 密钥

  1. 使用服务账户或管理员用户登录到 OCI 租户,然后转到用户设置

    打开用户设置

    或者

    从 OCI IAM 控制台转至用户。确保用户具有在 OCI 上创建和更新基础结构所需的所有访问权限。

  2. 转到资源部分,单击 API 密钥添加 API 密钥。选择此项可下载新的公钥和私钥、上载公钥或粘贴公钥。

    添加 API 密钥

  3. 将密钥保存在方便的位置,然后保存配置文件,如下页中所示。使用 REST API 连接到租户时,您需要此配置文件和私钥。

    保存配置文件

    注:

    • 您需要相同的 configuration parameters 才能连接到 OCI 区域和租户。在我们深入学习本教程时,您将相应地替换 Java 代码和 shell 脚本中的参数。

    • 为了从 OCI Compute 实例调用 OCI 服务,OCI 提供了一种更安全的方式来使用实例主体。避免使用用户 API 密钥作为最佳实践。有关更多信息,请参见 Calling Services from an Instance

任务 2:创建和运行 Shell 脚本以使用 REST API 从 OCI 对象存储上载或放置二进制文件

  1. 转到文件系统并创建 shell 文件。对于此示例,名为 PUT_OBJECT_REST_API.sh 的文件。

  2. 使用您选择的编辑器打开该文件,并将以下代码粘贴到 shell 文件中。

    • PUT_OBJECT_REST_API.sh:

      #!/bin/bash
      
      ########################## Fill these in with your values ##########################
      #OCID of the tenancy calls are being made in to
      tenancy_ocid="ocid1.tenancy.oc1..aaaaaaaackopa"
      
      # namespace of the tenancy
      namespace="ocitenancyname"
      
      # OCID of the user making the rest call
      user_ocid="ocid1.user.oc1..aaaaaaaafelqsoffcjh"
      
      # path to the private PEM format key for this user
      privateKeyPath="/home/lovelesh/.oci/oci_api_key.pem"
      
      # fingerprint of the private key for this user
      fingerprint="72:d4:6c:f8:89"
      
      #bucket name for uplaod/ put
      bucket="ocibucketname"
      
      #file name for upload/ put
      object="test_pdf.pdf"
      
      # The REST api you want to call, with any required paramters.
      rest_api="/n/$namespace/b/$bucket/o/$object"
      
      # The host you want to make the call against
      host="objectstorage.us-ashburn-1.oraclecloud.com"
      
      # the file containing the data you want to POST to the rest endpoint
      body="/home/lovelesh/.oci/test_pdf.pdf"
      ####################################################################################
      
      # extra headers required for a POST/PUT request
      method="put"
      content_type="application/octet-stream"
      body_arg=(--data-binary @${body})
      content_sha256="$(openssl dgst -binary -sha256 < $body | openssl enc -e -base64)";
      content_sha256_header="x-content-sha256: $content_sha256"
      content_length="$(wc -c < $body | xargs)";
      content_length_header="content-length: $content_length"
      headers="(request-target) date host"
      # add on the extra fields required for a POST/PUT
      headers=$headers" x-content-sha256 content-type content-length"
      content_type_header="content-type: $content_type";
      
      date=`date -u "+%a, %d %h %Y %H:%M:%S GMT"`
      date_header="date: $date"
      host_header="host: $host"
      request_target="(request-target): $method $rest_api"
      
      # note the order of items. The order in the signing_string matches the order in the headers, including the extra POST fields
      signing_string="$request_target\n$date_header\n$host_header"
      # add on the extra fields required for a POST/PUT
      signing_string="$signing_string\n$content_sha256_header\n$content_type_header\n$content_length_header"
      
      
      
      signature=`printf '%b' "$signing_string" | openssl dgst -sha256 -sign $privateKeyPath | openssl enc -e -base64 | tr -d '\n'`
      
      set -x
      curl -v -X $(echo $method | tr [:lower:] [:upper:]) --data-binary "@$body" -sS https://$host$rest_api -H "date: $date" -H "x-content-sha256: $content_sha256" -H "content-type: $content_type" -H "content-length: $content_length" -H "Authorization: Signature version=\"1\",keyId=\"$tenancy_ocid/$user_ocid/$fingerprint\",algorithm=\"rsa-sha256\",headers=\"$headers\",signature=\"$signature\""
      
  3. 现在我们在 shell 文件中粘贴了所有代码,让我们继续更新所需的值并了解其功能。

    tenancy_ocid="ocid1.tenancy.oc1..aaaaaaaackopa"
    ...
    fingerprint="72:d4:6c:f8:89"
    

    所有这些值负责与您的 OCI 租户建立安全连接。从配置文件中获取这些值。

    rest_api="/n/$namespace/b/$bucket/o/$object"
    host="objectstorage.us-ashburn-1.oraclecloud.com"
    

    这是 rest_apihost 端点,根据您的要求进行准备,因为每项服务都将发生更改。此处显示的示例是阿什本区域的 OCI 对象存储服务的端点。

    headers=$headers" x-content-sha256 content-type content-length"
    content_type_header="content-type: $content_type";
    date=`date -u "+%a, %d %h %Y %H:%M:%S GMT"`
    date_header="date: $date"
    host_header="host: $host"
    request_target="(request-target): $method $rest_api"
    

    在此处,我们为 REST API 创建了标头以及内容类型和其他必需参数。请注意,这里有 method_typedatehost header 的定义,对于后调用,我们需要设置详细的标头。

    signing_string="$signing_string\n$content_sha256_header\n$content_type_header\n$content_length_header"
    curl -v -X $(echo $method | tr [:lower:] [:upper:]) --data-binary "@$body" ...
    

    最后,我们将创建签名字符串,然后使用 curl 进行 REST API 调用。请注意,OCI 需要对 API 调用进行签名,这就是我们在这里执行此操作的原因。

  4. 根据您的配置更新值后,运行 shell 脚本,您应该看到该脚本执行正常,并且文件会推送到 OCI 对象存储。

    注:

    • 通过将 shell 文件权限更改为 755 或自行管理,确保已将 shell 文件权限更新为可执行文件。

    • 你也可以使用 powerhell 在 Windows 上这样做,或者在 Windows 上使用相同的脚本,方法是安装像 Ubuntu 这样的 WSL(Windows Subsystem for Linux),并在 Windows 上从 Ubuntu WSL 运行它。有关更多信息,请参见 Windows Subsystem for Linux

任务 3:创建并运行 Java 代码,以使用 REST API 从 OCI 对象存储上载或放置二进制文件

  1. 转到文件系统并创建 java 文件。对于此示例,名为 PUT_OBJECT_REST_API.java 的文件。

  2. 使用您选择的编辑器打开该文件,并将以下代码粘贴到 shell 文件中。

    • PUT_OBJECT_REST_API.java:

      import java.io.IOException;
      import java.net.URI;
      import java.net.http.HttpClient;
      import java.net.http.HttpRequest;
      import java.net.http.HttpResponse;
      import java.nio.file.Files;
      import java.nio.file.Paths;
      import java.security.KeyFactory;
      import java.security.NoSuchAlgorithmException;
      import java.security.PrivateKey;
      import java.security.Signature;
      import java.security.spec.InvalidKeySpecException;
      import java.security.spec.PKCS8EncodedKeySpec;
      import java.time.ZoneOffset;
      import java.time.ZonedDateTime;
      import java.time.format.DateTimeFormatter;
      import java.util.Base64;
      
      // NOTE - Feel free to remove logging as needed. Currently logs the signing string, host, date, and response. 
      
      public class PUT_OBJECT_REST_API {
      
          private static final String apiKeyFilePath = "C:\\Users\\User1\\Folder\\privatekey.pem"
          private static final String tenancyId = "ocid1.tenancy.oc1..aaaaaaaackopa27emaz4uteg4q7"; // OCI Tenancy ID
          private static final String userId = "ocid1.user.oc1..aaaaaaaafelqsoffcjq"; // OCI User ID
          private static final String keyFingerprint = "72:d4:6c:f8:89:74:aa"; // OCI fingerprint
          private static final String region = "us-ashburn-1"; // OCI Region
          private static final String namespace = "ocitenancyname"; // OCI bucket namespace
          private static final String bucketName = "ocibucketname"; // OCI bucket NAME
      
          public static void main(String[] args) {
              try {
                  String filePath = "D:\\file\\location\\test_pdf.pdf"; //args.length > 0 ? args[0] : ""; // File to upload (path)
                  PrivateKey privateKey = loadPrivateKey(apiKeyFilePath);
                  String fileName = Paths.get(filePath).getFileName().toString();
                  String targetUri = "https://objectstorage." + region + ".oraclecloud.com/n/" + namespace + "/b/" + bucketName + "/o/" + fileName;
                  HttpRequest request = buildRequest(targetUri, filePath, privateKey);
                  HttpClient client = HttpClient.newHttpClient();
                  HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
      
                  System.out.println("Response status code: " + response.statusCode());
                  System.out.println("Response body: " + response.body());
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      
          private static PrivateKey loadPrivateKey(String filePath) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
              String key = new String(Files.readAllBytes(Paths.get(filePath)))
                  .replace("-----BEGIN PRIVATE KEY-----", "")
                  .replace("-----END PRIVATE KEY-----", "")
                  .replaceAll("\\s+", ""); // Remove all whitespace
      
              byte[] decodedKey = Base64.getDecoder().decode(key);
              PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decodedKey);
              KeyFactory kf = KeyFactory.getInstance("RSA");
              return kf.generatePrivate(spec);
          }
      
          private static HttpRequest buildRequest(String targetUri, String filePath, PrivateKey privateKey) throws Exception {
              String method = "put";
              String path = "/n/" + namespace + "/b/" + bucketName + "/o/" + Paths.get(filePath).getFileName();
              String host = "objectstorage." + region + ".oraclecloud.com";
              String date = DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now(ZoneOffset.UTC));
              byte[] fileContent = Files.readAllBytes(Paths.get(filePath)); // Read file content as byte array
      
              String signingString = "(request-target): " + method.toLowerCase() + " " + path + "\n" +
                                  "host: " + host + "\n" +
                                  "date: " + date;
              System.out.println("Signing String: \n" + signingString);
      
              String signature = signRequest(privateKey, signingString);
              String authorizationHeader = "Signature version=\"1\",headers=\"(request-target) host date\",keyId=\"" +
                  tenancyId + "/" + userId + "/" + keyFingerprint + "\",algorithm=\"rsa-sha256\",signature=\"" + signature + "\"";
      
              return HttpRequest.newBuilder()
                      .uri(URI.create(targetUri))
                      .header("Content-Type", "application/octet-stream")
                      .header("date", date)
                      .header("Authorization", authorizationHeader)
                      .PUT(HttpRequest.BodyPublishers.ofByteArray(fileContent))
                      .build();
          }
      
          private static String signRequest(PrivateKey privateKey, String dataToSign) throws Exception {
              Signature signatureInstance = Signature.getInstance("SHA256withRSA");
              signatureInstance.initSign(privateKey);
              signatureInstance.update(dataToSign.getBytes());
              byte[] signature = signatureInstance.sign();
              return Base64.getEncoder().encodeToString(signature);
          }
      }
      
  3. 现在,我们已将所有代码粘贴到 java 文件中,让我们继续更新所需的值并了解其功能。

    private static final String apiKeyFilePath = "C:\\Users\\User1\\Folder\\privatekey.pem"
    private static final String tenancyId = "ocid1.tenancy.oc1..aaaaaaaackopa27emaz4uteg4q7"; // OCI Tenancy ID
    private static final String userId = "ocid1.user.oc1..aaaaaaaafelqsoffcjq"; // OCI User ID
    private static final String keyFingerprint = "72:d4:6c:f8:89:74:aa"; // OCI fingerprint
    private static final String region = "us-ashburn-1"; // OCI Region
    private static final String namespace = "ocitenancyname"; // OCI bucket namespace
    private static final String bucketName = "ocibucketname"; // OCI bucket NAME
    

    所有这些值负责与您的 OCI 租户建立安全连接。从配置文件中获取这些值。

    String targetUri = "https://objectstorage." + region + ".oraclecloud.com/n/" + namespace + "/b/" + bucketName + "/o/" + fileName;
    HttpRequest request = buildRequest(targetUri, filePath, privateKey);
    

    这是 rest_api 和主机端点,根据您的要求进行准备,因为每项服务都将发生更改。此处显示的示例是阿什本区域的 OCI 对象存储服务的端点。

    private static HttpRequest buildRequest
    

    我们已为 REST API 创建了标头以及内容类型和其他必需参数。请注意,这里有 method_type、日期和主机标头的定义,对于调用后,我们需要详细的标头集。

    private static String signRequest
    

    最后,我们将创建签名字符串,然后执行 REST API 调用。请注意,OCI 需要对 API 调用进行签名,这就是我们在此处执行该操作的原因。

  4. 根据您的配置更新值后,运行 java 代码,您应该会看到脚本执行正常,并将文件推送到 OCI 对象存储。

    注:请确保已根据代码需要安装了所有必需程序包的 Java。

确认

更多学习资源

浏览 docs.oracle.com/learn 上的其他实验室,或者访问 Oracle Learning YouTube 渠道上的更多免费学习内容。此外,请访问 education.oracle.com/learning-explorer 成为 Oracle Learning Explorer。

有关产品文档,请访问 Oracle 帮助中心