在OSS中,使用HTTP请求的Authorization Header来携带签名信息是进行身份验证的最常见方法。除了使用POST签名和URL签名之外,所有的OSS操作都需要通过Authorization Header来进行身份验证。本文介绍如何使用V4签名算法来在Header中包含签名。
SDK签名实现
OSS SDK已实现自动完成V4签名。采用OSS SDK的方式发起请求,可以免去手动签名的过程。如何在初始化客户端时使用V4签名,以及SDK如何实现V4签名的代码示例如下表所示:
SDK | 客户端初始化示例 | SDK签名实现 |
Java | ||
PHP | ||
Node.js | ||
Browser.js | ||
Python | ||
Go | ||
C++ | ||
C |
Authorization参数说明
如果上述方式无法满足您的需求,例如使用REST API发起请求时,您需要手动计算SDK签名,需要获取发起REST API请求时所需的Authorization参数。Authorization
字段以空格的形式分隔签名版本和签名信息。
Authorization字段 | 说明 |
签名版本 | 仅支持填写OSS4-HMAC-SHA256。 |
签名信息 | 以键值对(key=value)的形式呈现。键值对之间用逗号分隔,键与值之间用等号连接。其中,签名信息支持的key包括两个必选字段(
|
格式
Authorization: "OSS4-HMAC-SHA256 Credential=" + AccessKeyId + "/" + SignDate + "/" + SignRegion + "/oss/aliyun_v4_request, " + [ "AdditionalHeaders=" + AdditionalHeadersVal + ", " ] + "Signature=" + SignatureVal
示例
Authorization: OSS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20231203/cn-hangzhou/oss/aliyun_v4_request, AdditionalHeaders=host;userdefine, Signature=4b663e424d2db9967401ff6ce1c86f8c83cabd77d9908475239d9110642c63fa
通过STS服务获取的临时访问凭证发送请求时,您还需要将获得的security-token值以x-oss-security-token:security-token
的形式加入到请求头中。关于如何获取Security-Token的具体操作,请参见AssumeRole - 获取扮演角色的临时身份凭证。
签名计算流程
如下是签名计算流程图。
步骤一:通过Http verb等参数构建出的CanonicalReques字符串保留,在之后需要经过Hash转化;
步骤二:将步骤一中获得的CanonicalRequest进行一次sha256Hex转换得到字符串“XXX”,再将"OSS4-HMAC-SHA256"等参数与所得到的字符串“XXX”拼接,构建出StringToSign;
步骤三:根据图示使用HMAC-SHA256格式逐步转换封装参数,构建出SigningKey,最后将SigningKey与步骤二中获得的StringToSign使用HMAC-SHA256格式转换,得到的字符串就是Signature的值。
关于每个步骤的具体参数说明,请参考流程图下方各步骤内容。具体计算过程示例,请参考签名计算示例。
步骤1:构造CanonicalRequest
步骤2:构造待签名字符串(StringToSign)
步骤3:计算Signature
签名计算示例
以PutObject为例,演示如何在Header包含V4签名。
计算示例参数说明
参数
值
AccessKeyId
accesskeyid
AccessKeySecret
accesskeysecret
Timestamp
20231203T121212Z
Bucket
examplebucket
Object
exampleobject
Region
cn-hangzhou
PutObject
PUT /exampleobject HTTP/1.1 Content-MD5: eB5eJF1ptWaXm4bijSPyxw Content-Type: text/html Date: Sun, 03 Dec 2023 12:12:12 GMT Host: examplebucket.oss-cn-hangzhou.aliyuncs.com Authorization: SignatureToBeCalculated x-oss-date: 20231203T121212Z x-oss-meta-author: alice x-oss-meta-magic: abracadabra x-oss-content-sha256: UNSIGNED-PAYLOAD
在Header包含V4签名的步骤如下:
构造出的CanonicalRequest格式如下。
PUT /examplebucket/exampleobject content-md5:eB5eJF1ptWaXm4bijSPyxw content-type:text/html host:examplebucket.oss-cn-hangzhou.aliyuncs.com x-oss-content-sha256:UNSIGNED-PAYLOAD x-oss-date:20231203T121212Z x-oss-meta-author:alice x-oss-meta-magic:abracadabra host UNSIGNED-PAYLOAD
构造待签名字符串(StringToSign)格式如下。
OSS4-HMAC-SHA256 20231203T121212Z 20231203/cn-hangzhou/oss/aliyun_v4_request 129b14df88496f434606e999e35dee010ea1cecfd3ddc378e5ed4989609c1db3
计算签名。
计算SigningKey。
HMAC-SHA256(HMAC-SHA256(HMAC-SHA256(HMAC-SHA256("aliyun_v4" + "accesskeysecret", "20231203"), "cn-hangzhou"), "oss"), "aliyun_v4_request");
通过计算公式逐层计算得到Signature,结果格式示例如下。
说明计算公式为Signature = HEX(HMAC-SHA256(Signingkey,StringToSign));
4b663e424d2db9967401ff6ce1c86f8c83cabd77d9908475239d9110642c63fa
将签名添加到Authorization中。
OSS4-HMAC-SHA256 Credential=accesskeyid/20231203/cn-hangzhou/oss/aliyun_v4_request,AdditionalHeaders=host,Signature=4b663e424d2db9967401ff6ce1c86f8c83cabd77d9908475239d9110642c63fa
代码示例
import com.aliyun.oss.common.utils.BinaryUtil;
import org.apache.commons.codec.digest.DigestUtils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
/**
* Signature Demo
*/
public class Demo1 {
/**
* 签名计算工具
*
* @return Authorization
*/
public static void main(String[] args) throws Exception {
// 步骤1:构造CanonicalRequest
String canonicalRequest =
"PUT\n" +
"/examplebucket/exampleobject\n" +
"\n" +
"content-md5:eB5eJF1ptWaXm4bijSPyxw\n" +
"content-type:text/html\n" +
"host:examplebucket.oss-cn-hangzhou.aliyuncs.com\n" +
"x-oss-content-sha256:UNSIGNED-PAYLOAD\n" +
"x-oss-date:20231203T121212Z\n" +
"x-oss-meta-author:alice\n" +
"x-oss-meta-magic:abracadabra\n" +
"\n" +
"host\n" +
"UNSIGNED-PAYLOAD";
// 步骤2:构造待签名字符串(StringToSign)
String stringToSign = "OSS4-HMAC-SHA256\n" +
"20231203T121212Z\n" +
"20231203/cn-hangzhou/oss/aliyun_v4_request\n" +
DigestUtils.sha256Hex(canonicalRequest);
// 步骤3:计算Signature。
// "accesskeysecret"填入RAM用户的AccessKeySecret,data参数填入实际日期如"20231203”
byte[] dateKey = hmacsha256(("aliyun_v4" + "accesskeysecret").getBytes(), "20231203");
// 参数填入所在地区,如所在地域为杭州则填入"cn-hangzhou”
byte[] dateRegionKey = hmacsha256(dateKey, "cn-hangzhou");
byte[] dateRegionServiceKey = hmacsha256(dateRegionKey, "oss");
byte[] signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request");
byte[] result = hmacsha256(signingKey, stringToSign);
String signature = BinaryUtil.toHex(result);
System.out.println("signature:" + signature);
String authorization = "OSS4-HMAC-SHA256 " +
"Credential=accesskeyid/20231203/cn-hangzhou/oss/aliyun_v4_request," +
"AdditionalHeaders=host," +
"Signature=" + signature;
System.out.println("Authorization:" + authorization);
}
public static byte[] hmacsha256(byte[] key, String data) {
try {
// 初始化HMAC密钥规格,指定算法为HMAC-SHA256并使用提供的密钥。
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacSHA256");
// 获取Mac实例,并通过getInstance方法指定使用HMAC-SHA256算法。
Mac mac = Mac.getInstance("HmacSHA256");
// 使用密钥初始化Mac对象。
mac.init(secretKeySpec);
// 执行HMAC计算,通过doFinal方法接收需要计算的数据并返回计算结果的数组。
byte[] hmacBytes = mac.doFinal(data.getBytes());
return hmacBytes;
} catch (Exception e) {
throw new RuntimeException("Failed to calculate HMAC-SHA256", e);
}
}
}