在使用OCI Java SDK调用自定义REST请求时,生成符合规范的认证签名是接口鉴权的核心步骤,OCI采用基于请求信息的签名机制验证调用方身份,签名错误会直接导致请求返回401未授权错误。

OCI认证签名的核心组成
OCI的签名由请求的关键信息拼接后通过私钥加密生成,需要包含的核心元素有:
- 请求方法,比如GET、POST等
- 请求路径,包含接口的路径和查询参数
- 请求头中的必要字段,比如host、date、content-type等
- 请求体的哈希值,如果是GET等无请求体的请求则需要处理为空值的哈希
- 签名版本和算法标识,OCI当前常用的是1和RSA-SHA256
准备工作
在生成签名前需要先完成以下准备:
- 在OCI控制台创建用户,获取用户的OCID
- 创建API密钥对,将公钥上传到OCI用户设置中,保存好私钥文件
- 获取租户OCID、区域名称等基础配置信息
- 在项目中引入OCI Java SDK依赖,Maven配置如下:
<dependency>
<groupId>com.oracle.oci.sdk</groupId>
<artifactId>oci-java-sdk-common</artifactId>
<version>3.25.1</version>
</dependency>使用SDK生成签名的步骤
1. 加载私钥和配置基础信息
首先从私钥文件中加载私钥,同时初始化租户、用户、区域等配置:
import com.oracle.bmc.auth.AuthenticationDetailsProvider;
import com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider;
import com.oracle.bmc.http.ClientConfigurator;
import com.oracle.bmc.http.signing.DefaultRequestSigner;
import com.oracle.bmc.http.signing.RequestSigner;
import com.oracle.bmc.http.signing.SigningStrategy;
import com.oracle.bmc.model.Range;
import java.io.IOException;
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.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
public class OciSignDemo {
// 基础配置信息,替换为实际值
private static final String TENANT_ID = "ocid1.tenancy.oc1..your_tenant_id";
private static final String USER_ID = "ocid1.user.oc1..your_user_id";
private static final String FINGERPRINT = "your_key_fingerprint";
private static final String REGION = "us-ashburn-1";
private static final String PRIVATE_KEY_PATH = "/path/to/your/private_key.pem";
// 加载私钥方法
private static PrivateKey loadPrivateKey(String path) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
String keyContent = new String(Files.readAllBytes(Paths.get(path)));
// 去除PEM格式的头尾标识和换行
keyContent = keyContent.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s", "");
byte[] keyBytes = Base64.getDecoder().decode(keyContent);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(keySpec);
}
}2. 构造待签名的请求信息
需要把自定义REST请求的方法、路径、头信息、请求体等信息整理成SDK要求的格式:
import com.oracle.bmc.http.internal.Entity;
import com.oracle.bmc.http.internal.SdkHttpDetails;
import com.oracle.bmc.http.signing.RequestSigningException;
import com.oracle.bmc.http.signing.SignedRequest;
import com.oracle.bmc.http.signing.internal.DefaultSignedRequest;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
public class OciSignDemo {
// 前面的代码省略...
public static void main(String[] args) throws Exception {
// 加载私钥
PrivateKey privateKey = loadPrivateKey(PRIVATE_KEY_PATH);
// 构造认证信息提供者
AuthenticationDetailsProvider provider = SimpleAuthenticationDetailsProvider.builder()
.tenantId(TENANT_ID)
.userId(USER_ID)
.fingerprint(FINGERPRINT)
.privateKey(privateKey)
.region(REGION)
.build();
// 自定义REST请求信息
String requestMethod = "POST";
String requestUrl = "https://objectstorage.us-ashburn-1.oraclecloud.com/n/your_namespace/b/your_bucket/o/your_object";
String requestBody = "{\"name\":\"test\"}";
Map<String, String> requestHeaders = new HashMap<>();
requestHeaders.put("content-type", "application/json");
requestHeaders.put("date", "Mon, 01 Jan 2024 00:00:00 GMT");
requestHeaders.put("host", "objectstorage.us-ashburn-1.oraclecloud.com");
// 构造请求URI
URI uri = new URI(requestUrl);
}
}3. 生成签名并添加到请求头
使用OCI Java SDK内置的签名工具生成签名,并将签名相关头信息添加到请求中:
import com.oracle.bmc.http.signing.RequestSigner;
import com.oracle.bmc.http.signing.internal.DefaultRequestSigner;
import java.util.List;
import java.util.Map;
public class OciSignDemo {
// 前面的代码省略...
public static void main(String[] args) throws Exception {
// 前面的代码省略...
// 初始化签名器
RequestSigner signer = DefaultRequestSigner.builder()
.authenticationDetailsProvider(provider)
.signingStrategy(SigningStrategy.STANDARD)
.build();
// 构造待签名的请求对象
SdkHttpDetails httpDetails = new SdkHttpDetails() {
@Override
public String getHttpMethod() {
return requestMethod;
}
@Override
public URI getUri() {
return uri;
}
@Override
public Map<String, List<String>> getHeaders() {
Map<String, List<String>> headers = new HashMap<>();
requestHeaders.forEach((k, v) -> headers.put(k, List.of(v)));
return headers;
}
@Override
public Entity getEntity() {
if (requestBody != null && !requestBody.isEmpty()) {
return new Entity() {
@Override
public byte[] getContent() {
return requestBody.getBytes();
}
@Override
public long getContentLength() {
return requestBody.getBytes().length;
}
@Override
public String getContentType() {
return requestHeaders.get("content-type");
}
};
}
return null;
}
};
// 生成签名并获取签名头
SignedRequest signedRequest = signer.signRequest(httpDetails);
Map<String, List<String>> signedHeaders = signedRequest.getHeaders();
// 输出签名后的请求头,用于后续发送请求
System.out.println("签名后的请求头:");
signedHeaders.forEach((k, v) -> System.out.println(k + ": " + String.join(",", v)));
}
}常见问题排查
如果签名验证失败,可以从以下几个方向排查:
- 检查私钥是否和上传到OCI的公钥匹配,指纹是否正确
- 请求头中的date字段格式是否符合RFC1123规范,和实际时间偏差不超过5分钟
- 请求路径和查询参数是否和签名时使用的完全一致,不要做额外的编码处理
- 请求体的哈希计算是否正确,无请求体时要使用空字符串的SHA256哈希
- 签名版本和算法是否和OCI接口要求一致,当前大部分接口使用签名版本1
总结
借助OCI Java SDK生成自定义REST请求认证签名的核心是正确使用SDK内置的签名工具,提前准备好认证所需的基础信息,按照要求构造待签名的请求对象即可。签名生成后可以直接添加到自定义请求的头部,完成接口鉴权。实际使用中可以根据业务需求封装签名生成工具类,提升复用性。
OCI_Java_SDKREST请求认证签名API鉴权修改时间:2026-06-03 16:05:10