除了通过HTTP请求头部的Authorization字段进行签名授权外,您还可以生成一个包含签名和其他必要的请求信息的预签名URL。通过这种方式,您可以在不透露访问凭证的情况下,授予第三方在特定有效期内对OSS资源的访问权限。本文介绍如何使用V4签名算法实现在URL中包含签名。
SDK签名实现
OSS SDK已实现自动完成V4签名。推荐采用OSS SDK的方式发起请求,可以免去手动签名的过程。如果您想了解具体语言的签名实现,请参考OSS SDK的代码。OSS SDK签名实现的文件请参见下表。
SDK | 客户端初始化示例 | 签名实现 |
Java | ||
PHP | ||
Node.js | ||
Browser.js | ||
Python | ||
Go | ||
C++ | ||
C |
URL签名描述
示例
https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject?x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=<AccessKeyId>/20231203/cn-hangzhou/oss/aliyun_v4_request&x-oss-date=20231203T121212Z&x-oss-expires=86400&x-oss-additional-headers=host&x-oss-signature=<signature-to-be-calculated>
上述URL中的
x-oss-credential
的值为方便展示各个字段的参数,使用正斜线(/)进行分隔。在实际请求时,需要对URL中的/
执行UrlEncode,即转化成%2F
,示例如下:&x-oss-credential=<AccessKeyId>%2F20231203%2Fcn-hangzhou%2Foss%2Faliyun_v4_request
URL中的QueryString参数说明
参数
类型
是否必选
示例值
说明
x-oss-signature-version
字符串
是
OSS4-HMAC-SHA256
指定签名的版本和算法,固定值为OSS4-HMAC-SHA256。
x-oss-credential
字符串
是
LTAI********************/20231203/cn-hangzhou/oss/aliyun_v4_request
指明派生密钥的参数集,格式如下:
<AccessKeyId>/<date>/<region>/oss/aliyun_v4_request
AccessKeyId:填写访问密钥中的AccessKey ID。
date:填写请求的日期,
region:填写请求所在的Region。
oss:请求的服务名称,固定为oss。
aliyun_v4_request:请求的版本说明,固定为aliyun_v4_request。
x-oss-date
字符串
是
20231203T121212Z
签名URL的起始时间,为避免时钟误差,允许向后偏移15分钟,格式为ISO8601。
说明该时间用作StringToSign中的TimeStamp,取值必须与创建SigningKey中的Date是同一天。
x-oss-expires
整数
是
3600
签名URL的有效时长,单位为秒(s)。最小值为1,最大值为 604800(即7 天)。
x-oss-additional-headers
字符串
否
host
除默认要加入签名的Header以外,指定其他需要签名的Header。建议将请求中使用的所有Header都加入签名。
该字段的构建方法说明如下:
额外头部中的所有Header均要求小写。
按照字典序升序排列额外头部中的所有Header。
以分号连接数组中的元素,获取字符串。
x-oss-signature
字符串
是
77Dv****************
用于签名认证的描述信息。x-oss-signature不参与签名计算。
x-oss-security-token
字符串
否
CAIS********************************
STS安全令牌。仅当使用STS构造URL签名时,才需要设置此参数。
签名计算过程
URL签名计算方法与Header签名计算方法基本类似。但由于签名URL使用方法的不同,与Header签名计算仍存在以下差异:
签名URL的方式不包含描述payload的Header(
x-oss-content-sha256
)。原因是创建预签名时,无法预估实际传输的payload。因此,在URL签名过程中,直接使用UNSIGNED-PAYLOAD。如果签名URL的QueryParameter与待签名Header中的Key相同但Value不同的情况,会出现报错。同一个Key有多个Value的情况,会同时比较Key对应的所有Value,如果Value不一致也会出现报错。
签名URL中,如果通过STS访问OSS,必须在QueryString中添加x-oss-security-token。
QueryString中的x-oss-signature不参与签名。
步骤1:构造CanonicalRequest
步骤2:构造待签名字符串(StringToSign)
步骤3:计算Signature
签名计算示例
以创建一个预签名URL,分享给其他用户上传数据为例,演示如何在URL包含V4签名。
计算示例参数说明
参数
值
AccessKeyId
accesskeyid
AccessKeySecret
accesskeysecret
Timestamp
20231203T121212Z
Bucket
examplebucket
Object
exampleobject
Region
cn-hangzhou
PutObject
https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject?x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=accesskeyid/20231203/cn-hangzhou/oss/aliyun_v4_request&x-oss-date=20231203T121212Z&x-oss-expires=86400&x-oss-additional-headers=host&x-oss-signature=<signature-to-be-calculated> Host: examplebucket.oss-cn-hangzhou.aliyuncs.com x-oss-meta-author: alice x-oss-meta-magic: abracadabra
在URL包含V4签名的步骤如下:
构造CanonicalRequest。
PUT /examplebucket/exampleobject x-oss-additional-headers=host&x-oss-credential=accesskeyid%2F20231203%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-date=20231203T121212Z&x-oss-expires=86400&x-oss-signature-version=OSS4-HMAC-SHA256 host:examplebucket.oss-cn-hangzhou.aliyuncs.com 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 672d815902f04dd8aa90a558931f471cc7269d08a122a5e9028022d9f723332c
计算签名。
计算SigningKey。
说明为方便可读,如下为SigningKey经Base64编码后的字符串。
WVjaYR8lCj9YC5PUS2RSZQANYbuh9DhMFxjU1NtZKfc=
计算Signature。
2c6c9f10d8950fb150290ef6f42570e33cd45d6a57ec7887de75fa2ec45b4c72
在URL中加入签名。
https://examplebucket.oss-cn-hangzhou.aliyuncs.com?x-oss-additional-headers=host&x-oss-credential=accesskeyid%2F20231203%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-date=20231203T121212Z&x-oss-expires=86400&x-oss-signature=2c6c9f10d8950fb150290ef6f42570e33cd45d6a57ec7887de75fa2ec45b4c72&x-oss-signature-version=OSS4-HMAC-SHA256 Host: examplebucket.oss-cn-hangzhou.aliyuncs.com x-oss-meta-author: alice x-oss-meta-magic: abracadabra
签名计算完整示例代码
以上述签名计算示例提供的参数为例,通过Java示例代码演示签名计算的完整过程。
import com.aliyun.oss.common.utils.BinaryUtil;
import org.apache.commons.codec.digest.DigestUtils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URL;
public class Demo {
/**
* 签名计算工具
*
* @return url
*/
public static void main(String[] args) throws Exception {
// 运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
String accesskeyid = System.getenv().get("OSS_ACCESS_KEY_ID");
String accesskeysecret = System.getenv().get("OSS_ACCESS_KEY_SECRET");
// 步骤1:构造CanonicalRequest。
String canonicalRequest =
"PUT\n" +
"/examplebucket/exampleobject\n" +
"x-oss-additional-headers=host&x-oss-credential="+accesskeyid+"%2F20231203%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-date=20231203T121212Z&x-oss-expires=86400&x-oss-signature-version=OSS4-HMAC-SHA256\n" +
"host:examplebucket.oss-cn-hangzhou.aliyuncs.com\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。
byte[] dateKey = hmacsha256(("aliyun_v4" + accesskeysecret).getBytes(), "20231203");
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);
// 步骤4:在URL中加入签名。
String resourcePath = "exampleobject";
String endpoint = "https://examplebucket.oss-cn-hangzhou.aliyuncs.com";
String queryString = "x-oss-additional-headers=host&" +
"x-oss-credential="+accesskeyid+"%2F20231203%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&" +
"x-oss-date=20231203T121212Z&" +
"x-oss-expires=86400&" +
"x-oss-signature=" + signature + "&" +
"x-oss-signature-version=OSS4-HMAC-SHA256";
String urlStr = endpoint + "/" + resourcePath + "?" + queryString;
URL url = new URL(urlStr);
System.out.println("url:" + url);
}
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);
}
}
}
返回结果如下:
signature:2c6c9f10d8950fb150290ef6f42570e33cd45d6a57ec7887de75fa2ec45b4c72
url:https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject?x-oss-additional-headers=host&x-oss-credential=accesskeyid%2F20231203%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-date=20231203T121212Z&x-oss-expires=86400&x-oss-signature=2c6c9f10d8950fb150290ef6f42570e33cd45d6a57ec7887de75fa2ec45b4c72&x-oss-signature-version=OSS4-HMAC-SHA256