
本文旨在指导读者如何利用 Oracle OCI Java SDK 的请求签名功能,为自定义 REST API 调用生成符合 OCI 认证要求的 `Authorization` 和 `Date` 头。不同于直接获取“令牌”,OCI 认证基于请求签名机制。我们将详细介绍如何配置身份验证提供程序,获取并使用 `RequestSigner` 接口,从而确保您的自定义 HTTP 请求能够被 OCI 服务正确验证。
Oracle Cloud Infrastructure (OCI) 的 API 认证机制主要基于请求签名。这意味着,当您向 OCI 服务发送请求时,SDK 或您的应用程序需要使用预配置的身份验证凭据(如 API 密钥)对请求的特定部分(包括 HTTP 方法、路径、查询参数、请求体哈希等)进行加密签名。生成的签名连同其他认证信息(如密钥指纹、租户 OCID 等)被放置在 Authorization HTTP 头中。此外,请求的 Date 头也扮演着关键角色,用于防止重放攻击,并与签名过程紧密关联。
OCI Java SDK 通常会自动处理这些复杂的签名过程。当您使用 SDK 提供的服务客户端(例如 ObjectStorageClient 或 ComputeClient)时,SDK 会透明地管理请求的构建、签名和发送。然而,在某些特定场景下,您可能需要使用自定义的 HTTP 客户端(如 java.net.http.HttpClient、Apache HttpClient 或 OkHttp)来直接与 OCI REST API 交互,此时就需要手动生成符合 OCI 规范的 Authorization 和 Date 头。
用户常见的误解是试图从 SDK 中直接获取一个“令牌”(token)来放入 Authorization 头。实际上,OCI 的认证并非基于短期的 bearer token 机制,而是每次请求都需要重新计算签名的过程。
立即学习“Java免费学习笔记(深入)”;
为了支持自定义 HTTP 客户端的认证需求,OCI Java SDK 提供了一个名为 RequestSigner 的接口。这个接口的目的是将 OCI 复杂的请求签名逻辑暴露给开发者,以便他们可以对任何自定义的 HTTP 请求进行签名,而无需深入了解签名算法的细节。
RequestSigner 的核心功能是接收一个表示 HTTP 请求的对象,并返回一个包含所有必要认证头的映射。这些头通常包括 Authorization 和 Date,以及其他可能的签名相关头。通过使用 RequestSigner,您可以:
在使用 RequestSigner 之前,您需要配置一个 AuthenticationDetailsProvider。这是 OCI Java SDK 中用于提供认证凭据的核心组件。根据您的运行环境,可以选择不同的实现:
ConfigFileAuthenticationDetailsProvider:
用途: 主要用于本地开发、测试或任何可以访问 OCI 配置文件 (~/.oci/config) 的环境。
配置: 从 OCI 配置文件中读取用户 OCID、租户 OCID、区域、API 密钥路径和指纹。
示例:
import com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider;
import java.io.IOException;
// 默认会查找 ~/.oci/config 文件和 [DEFAULT] 配置项
// 您也可以指定配置文件的路径和配置项的 profile
ConfigFileAuthenticationDetailsProvider provider = new ConfigFileAuthenticationDetailsProvider("~/.oci/config", "DEFAULT");InstancePrincipalsAuthenticationDetailsProvider:
用途: 当您的应用程序运行在 OCI 计算实例上时,推荐使用此提供程序。它利用实例主体(Instance Principal)的身份验证,无需在实例上存储 API 密钥。
配置: 自动从实例元数据服务获取凭据。
示例:
import com.oracle.bmc.auth.InstancePrincipalsAuthenticationDetailsProvider;
InstancePrincipalsAuthenticationDetailsProvider provider =
InstancePrincipalsAuthenticationDetailsProvider.builder().build();ResourcePrincipalAuthenticationDetailsProvider:
用途: 当您的应用程序运行在 OCI 函数、容器实例或其他资源主体(Resource Principal)支持的服务中时,推荐使用此提供程序。
配置: 自动从环境或元数据服务获取凭据。
示例:
import com.oracle.bmc.auth.ResourcePrincipalAuthenticationDetailsProvider;
ResourcePrincipalAuthenticationDetailsProvider provider =
ResourcePrincipalAuthenticationDetailsProvider.builder().build();选择合适的 AuthenticationDetailsProvider 是第一步,它将作为创建 RequestSigner 的基础。
一旦您有了 AuthenticationDetailsProvider 实例,就可以使用它来构建一个 RequestSigner。RequestSigner 接口定义了 signRequest() 方法,该方法接受一个 com.oracle.bmc.http.internal.ResponseHelper.Request 对象(一个 SDK 内部定义的请求抽象)并返回一个包含签名头的 Map<String, String>。
由于 RequestSigner 期望的是 SDK 内部的 Request 对象,您需要将自定义 HTTP 客户端的请求转换为这种格式。SDK 提供了一个辅助类 com.oracle.bmc.http.signing.internal.RequestSignerImpl,它实现了 RequestSigner 接口。
以下是使用 RequestSigner 的基本步骤和示例代码:
添加必要的 Maven 依赖 确保您的 pom.xml 中包含 OCI Java SDK 的通用模块,它包含了 RequestSigner 及其相关类:
<dependency>
<groupId>com.oracle.oci.sdk</groupId>
<artifactId>oci-java-sdk-common</artifactId>
<version>2.x.x</version> <!-- 使用最新版本 -->
</dependency>
<dependency>
<groupId>com.oracle.oci.sdk</groupId>
<artifactId>oci-java-sdk-addons-jackson-databind</artifactId>
<version>2.x.x</version> <!-- 使用最新版本,如果需要JSON处理 -->
</dependency>
<!-- 如果您使用 java.net.http.HttpClient,则无需额外依赖 -->示例代码:使用 RequestSigner 签名自定义 HTTP 请求
import com.oracle.bmc.auth.AuthenticationDetailsProvider;
import com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider;
import com.oracle.bmc.http.internal.ResponseHelper;
import com.oracle.bmc.http.signing.RequestSigner;
import com.oracle.bmc.http.signing.internal.RequestSignerImpl;
import com.oracle.bmc.http.signing.internal.Constants;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
public class OciCustomApiSigner {
public static void main(String[] args) throws IOException, InterruptedException {
// 1. 配置身份验证提供程序
// 假设您已在 ~/.oci/config 中配置了 [DEFAULT] profile
AuthenticationDetailsProvider provider;
try {
provider = new ConfigFileAuthenticationDetailsProvider("~/.oci/config", "DEFAULT");
} catch (IOException e) {
System.err.println("无法加载 OCI 配置文件或 profile。请确保文件存在且配置正确。");
e.printStackTrace();
return;
}
// 2. 创建 RequestSigner 实例
// RequestSignerImpl 是 RequestSigner 接口的默认实现
RequestSigner requestSigner = new RequestSignerImpl(provider);
// 3. 定义要签名的自定义 HTTP 请求的详细信息
String method = "GET"; // HTTP 方法
URI uri = URI.create("https://objectstorage.us-ashburn-1.oraclecloud.com/n/your_namespace/b/your_bucket_name/"); // 目标 URI
Map<String, String> headers = new HashMap<>();
// OCI API 通常需要 Host 头
headers.put("Host", uri.getHost());
// 如果有请求体,需要计算其 SHA256 摘要并添加到 headers 中
// 对于 GET 请求,通常没有请求体
// 4. 将自定义请求转换为 RequestSigner 期望的 Request 对象
// 注意:ResponseHelper.Request 是 SDK 内部类,但在此场景下是必需的
ResponseHelper.Request.Builder requestBuilder = ResponseHelper.Request.builder();
requestBuilder.method(method);
requestBuilder.uri(uri);
requestBuilder.headers(headers);
// 如果是 PUT/POST 请求且有请求体,需要设置 body 和 content-length
// byte[] requestBodyBytes = "{\"key\": \"value\"}".getBytes(java.nio.charset.StandardCharsets.UTF_8);
// requestBuilder.body(new ByteArrayInputStream(requestBodyBytes));
// requestBuilder.header("Content-Length", String.valueOf(requestBodyBytes.length));
// requestBuilder.header("Content-Type", "application/json");
ResponseHelper.Request ociRequest = requestBuilder.build();
// 5. 调用 RequestSigner 对请求进行签名
Map<String, String> signedHeaders = requestSigner.signRequest(ociRequest);
System.out.println("生成的签名头信息:");
signedHeaders.forEach((key, value) -> System.out.println(key + ": " + value));
// 6. 使用签名的头信息构建并发送实际的 HTTP 请求
HttpClient httpClient = HttpClient.newBuilder().build();
HttpRequest.Builder httpRequestBuilder = HttpRequest.newBuilder()
.uri(uri)
.method(method, HttpRequest.BodyPublishers.noBody()); // 对于GET请求,没有请求体
// 将签名后的头添加到实际的 HttpRequest 中
signedHeaders.forEach(httpRequestBuilder::header);
HttpRequest finalHttpRequest = httpRequestBuilder.build();
System.out.println("\n发送签名的 HTTP 请求...");
HttpResponse<String> response = httpClient.send(finalHttpRequest, HttpResponse.BodyHandlers.ofString());
System.out.println("HTTP 响应状态码: " + response.statusCode());
System.out.println("HTTP 响应体:\n" + response.body());
// 检查响应头中的 Opc-Request-Id,用于调试
Optional<String> opcRequestId = response.headers().firstValue("opc-request-id");
opcRequestId.ifPresent(id -> System.out.println("Opc-Request-Id: " + id));
}
}在上述示例中,RequestSigner 会自动生成 Authorization 和 Date 头,并将它们添加到 signedHeaders 映射中。您只需将这些头应用到您选择的 HTTP 客户端所构建的请求中即可。
通过 OCI Java SDK 提供的 RequestSigner 接口,开发者可以有效地为自定义 HTTP 请求生成符合 OCI 认证规范的 Authorization 和 Date 头。这消除了手动实现复杂签名逻辑的需要,并使得在不使用 SDK 服务客户端的情况下,也能安全、可靠地与 OCI REST API 进行交互。理解 OCI 基于签名的认证机制,并正确配置 AuthenticationDetailsProvider 和 RequestSigner,是成功实现这一目标的关键。在大多数情况下,SDK 提供的服务客户端是首选,但当您需要更细粒度的控制或集成现有 HTTP 客户端时,RequestSigner 是一个强大的工具。
以上就是使用 OCI Java SDK 签名自定义 REST API 请求的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号