注意:
- 本教程需要访问 Oracle Cloud。要注册免费账户,请参阅开始使用 Oracle Cloud Infrastructure 免费套餐。
- 它对 Oracle Cloud Infrastructure 身份证明、租户和区间使用示例值。完成实验室后,请使用特定于云环境的那些值替换这些值。
使用 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 示例。
目标
-
根据将连接到 OCI 租户的 REST API 为用户设置 OCI API 密钥。
-
创建用例以使用 REST API 下载二进制文件或将二进制文件上载到 OCI 对象存储。
-
设置 shell 和 Java 应用,编写适当的代码来调用和显示 OCI REST API。
先决条件
-
Oracle Cloud Infrastructure Identity and Access Management (OCI IAM) 中允许访问 OCI 和策略。用户应有权访问要使用 REST API 创建或更新的相应资源。
-
具有 shell 脚本编写和 Java 应用程序开发方面的知识。
-
对软件开发敏捷方法的基本理解。
任务 1:设置 Oracle Cloud Infrastructure API 密钥
-
使用服务账户或管理员用户登录到 OCI 租户,然后转到用户设置。
或者
从 OCI IAM 控制台转至用户。确保用户具有在 OCI 上创建和更新基础结构所需的所有访问权限。
-
转到资源部分,单击 API 密钥和添加 API 密钥。选择此项可下载新的公钥和私钥、上载公钥或粘贴公钥。
-
将密钥保存在方便的位置,然后保存配置文件,如下页中所示。使用 REST API 连接到租户时,您需要此配置文件和私钥。
注:
-
您需要相同的
configuration parameters
才能连接到 OCI 区域和租户。在我们深入学习本教程时,您将相应地替换 Java 代码和 shell 脚本中的参数。 -
为了从 OCI Compute 实例调用 OCI 服务,OCI 提供了一种更安全的方式来使用实例主体。避免使用用户 API 密钥作为最佳实践。有关更多信息,请参见 Calling Services from an Instance 。
-
任务 2:创建和运行 Shell 脚本以使用 REST API 从 OCI 对象存储上载或放置二进制文件
-
转到文件系统并创建 shell 文件。对于此示例,名为
PUT_OBJECT_REST_API.sh
的文件。 -
使用您选择的编辑器打开该文件,并将以下代码粘贴到 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\""
-
-
现在我们在 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_api 和 host 端点,根据您的要求进行准备,因为每项服务都将发生更改。此处显示的示例是阿什本区域的 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_type 、 date 和 host 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 调用进行签名,这就是我们在这里执行此操作的原因。
-
根据您的配置更新值后,运行 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 对象存储上载或放置二进制文件
-
转到文件系统并创建 java 文件。对于此示例,名为
PUT_OBJECT_REST_API.java
的文件。 -
使用您选择的编辑器打开该文件,并将以下代码粘贴到 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); } }
-
-
现在,我们已将所有代码粘贴到 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 调用进行签名,这就是我们在此处执行该操作的原因。
-
根据您的配置更新值后,运行 java 代码,您应该会看到脚本执行正常,并将文件推送到 OCI 对象存储。
注:请确保已根据代码需要安装了所有必需程序包的 Java。
相关链接
确认
- 作者 - Lovelesh Saxena(首席软件工程架构师)
更多学习资源
浏览 docs.oracle.com/learn 上的其他实验室,或者访问 Oracle Learning YouTube 渠道上的更多免费学习内容。此外,请访问 education.oracle.com/learning-explorer 成为 Oracle Learning Explorer。
有关产品文档,请访问 Oracle 帮助中心。
Manage Oracle Cloud Infrastructure REST APIs Programmatically using Shell and Java Code
G12005-01
July 2024