阿里云oss
具体步骤如下:
- 客户端向应用服务器发出上传文件到OSS的请求。
- 应用服务器向STS服务器请求一次,获取临时凭证。
- 应用服务器回复客户端,将临时凭证返回给客户端。
- 客户端获取上传到OSS的授权(STS的AccessKey以及Token),调用OSS提供的移动端SDK上传。
- 客户端成功上传数据到OSS。如果没有设置回调,则流程结束。如果设置了回调功能,OSS会调用相关的接口。
1、oss访问域名
通过外网访问OSS服务
<Schema>://<Bucket>.<外网Endpoint>/<Object>
- Schema:HTTP或者为HTTPS
- Bucket:OSS存储空间
- Endpoint:Bucket所在数据中心的访问域名,您需要填写外网Endpoint
- Object:上传到OSS上的文件
示例:如您的Region为华东1(oss-cn-hangzhou),Bucket名称为abc,Object名称为myfile/aaa.txt,那么您的外网访问地址为:
abc.oss-cn-hangzhou.aliyuncs.com/myfile/aaa.txt
2、访问授权获取
用户可以在HTTP请求中增加 Authorization 的Header来包含签名(Signature)信息,表明这个消息已被授权。
Authorization字段计算的方法
Authorization = "OSS " + AccessKeyId + ":" + Signature
Signature = base64(hmac-sha1(AccessKeySecret,
VERB + "\n"
+ Content-MD5 + "\n"
+ Content-Type + "\n"
+ Date + "\n"
+ CanonicalizedOSSHeaders
+ CanonicalizedResource))
AccessKeySecret表示签名所需的密钥。VERB表示HTTP 请求的Method,主要有PUT、GET、POST、HEAD、DELETE等。\n表示换行符。Content-MD5表示请求内容数据的MD5值,对消息内容(不包括头部)计算MD5值获得128比特位数字,对该数字进行base64编码而得到。该请求头可用于消息合法性的检查(消息内容是否与发送时一致),如”eB5eJF1ptWaXm4bijSPyxw==”,也可以为空。详情请参见RFC2616 Content-MD5。Content-Type表示请求内容的类型,如”application/octet-stream”,也可以为空。Date表示此次操作的时间,且必须为GMT格式,如”Sun, 22 Nov 2015 08:16:38 GMT”。CanonicalizedOSSHeaders表示以 x-oss- 为前缀的HTTP Header的字典序排列。CanonicalizedResource表示用户想要访问的OSS资源。
其中,Date和CanonicalizedResource不能为空;如果请求中的Date时间和OSS服务器的时间差15分钟以上,OSS服务器将拒绝该服务,并返回HTTP 403错误。
javascript实现:
构建CanonicalizedOSSHeaders的方法
所有以 x-oss- 为前缀的HTTP Header被称为CanonicalizedOSSHeaders。它的构建方法如下:
- 将所有以 x-oss- 为前缀的HTTP请求头的名字转换成小写 。如
X-OSS-Meta-Name: TaoBao转换成x-oss-meta-name: TaoBao。 - 如果请求是以STS获得的AccessKeyId和AccessKeySecret发送时,还需要将获得的security-token值以
x-oss-security-token:security-token的形式加入到签名字符串中。 - 将上一步得到的所有HTTP请求头按照名字的字典序进行升序排列。
- 删除请求头和内容之间分隔符两端出现的任何空格。如
x-oss-meta-name: TaoBao转换成:x-oss-meta-name:TaoBao。 - 将每一个头和内容用
\n分隔符分隔拼成最后的CanonicalizedOSSHeaders。
说明
- CanonicalizedOSSHeaders可以为空,无需添加最后的
\n。 - 如果只有一个,则如
x-oss-meta-a\n,注意最后的\n。 - 如果有多个,则如
x-oss-meta-a:a\nx-oss-meta-b:b\nx-oss-meta-c:c\n,注意最后的\n。
构建CanonicalizedResource的方法
用户发送请求中想访问的OSS目标资源被称为CanonicalizedResource。它的构建方法如下:
- 将CanonicalizedResource置成空字符串
""; - 放入要访问的OSS资源
/BucketName/ObjectName(如果没有ObjectName则CanonicalizedResource为”/BucketName/“,如果同时也没有BucketName则为“/”) - 如果请求的资源包括子资源(SubResource) ,那么将所有的子资源按照字典序,从小到大排列并以
&为分隔符生成子资源字符串。在CanonicalizedResource字符串尾添加?和子资源字符串。此时的CanonicalizedResource如:/BucketName/ObjectName?acl&uploadId=UploadId - 如果用户请求在指定了查询字符串(QueryString,也叫Http Request Parameters),那么将这些查询字符串及其请求值按照字典序,从小到大排列,以
&为分隔符,按参数添加到CanonicalizedResource中,如:/BucketName/ObjectName?acl&response-content-type=ContentType&uploadId=UploadId。
计算签名头规则
- 签名的字符串必须为
UTF-8格式。含有中文字符的签名字符串必须先进行UTF-8编码,再与AccessKeySecret计算最终签名。 - 签名的方法用RFC 2104中定义的HMAC-SHA1方法,其中Key为 AccessKeySecret` 。
Content-Type和Content-MD5在请求中不是必须的,但是如果请求需要签名验证,空值的话以换行符\n代替。- 在所有非HTTP标准定义的header中,只有以
x-oss-开头的header,需要加入签名字符串;其他非HTTP标准header将被OSS忽略(如上例中的x-oss-magic是需要加入签名字符串的)。 - 以
x-oss-开头的header在签名验证前需要符合以下规范:- header的名字需要变成小写。
- header按字典序自小到大排序。
- 分割header name和value的冒号前后不能有空格。
- 每个Header之后都有一个换行符“\n”,如果没有Header,CanonicalizedOSSHeaders就设置为空。
1、Date:
dateFormat(new Date(), 'UTC:ddd, dd mmm yyyy HH:MM:ss \'GMT\''),
2、Content-MD5
headers['Content-Md5'] = crypto
.createHash('md5')
.update(new Buffer(params.content, 'utf8'))
.digest('base64');
3、CanonicalizedOSSHeaders stsToken
headers['x-oss-security-token'] = stsToken;
4、CanonicalizedResource
/BucketName/ObjectName
计算resource
proto._getResource = function _getResource(params) {
let resource = '/';
if (params.bucket) resource += `${params.bucket}/`;
if (params.object) resource += params.object;
return resource;
};
5、创建签名字符串
exports.buildCanonicalString = function canonicalString(method, resourcePath, request, expires) {
request = request || {};
const headers = request.headers || {};
const OSS_PREFIX = 'x-oss-';
const ossHeaders = [];
const headersToSign = {};
let signContent = [
method.toUpperCase(),
headers['Content-Md5'] || '',
headers['Content-Type'] || headers['Content-Type'.toLowerCase()],
expires || headers['x-oss-date']
];
Object.keys(headers).forEach((key) => {
const lowerKey = key.toLowerCase();
if (lowerKey.indexOf(OSS_PREFIX) === 0) {
headersToSign[lowerKey] = String(headers[key]).trim();
}
});
Object.keys(headersToSign).sort().forEach((key) => {
ossHeaders.push(`${key}:${headersToSign[key]}`);
});
signContent = signContent.concat(ossHeaders);
signContent.push(this.buildCanonicalizedResource(resourcePath, request.parameters));
return signContent.join('\n');
};
计算签名
/**
* @param {String} accessKeySecret
* @param {String} canonicalString
*/
exports.computeSignature = function computeSignature(accessKeySecret, canonicalString) {
const signature = crypto.createHmac('sha1', accessKeySecret);
return signature.update(new Buffer(canonicalString, 'utf8')).digest('base64');
};
计算authoraion
/**
* @param {String} accessKeyId
* @param {String} accessKeySecret
* @param {String} canonicalString
*/
exports.authorization = function authorization(accessKeyId, accessKeySecret, canonicalString) {
return `OSS ${accessKeyId}:${this.computeSignature(accessKeySecret, canonicalString)}`;
};
浙公网安备 33010602011771号