• 关于 php 分割字符 的搜索结果

问题

PHP MySQL 关于文章字段内容分页的几个小问题

蛮大人123 2019-12-01 19:49:27 1442 浏览量 回答数 1

问题

PHP遍历时怎么不让变量重复叠加?报错

一枚小鲜肉帅哥 2020-06-01 23:44:34 1 浏览量 回答数 1

回答

详细解答可以参考官方帮助文档 用户可以在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错误。 构建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中。此时的CanonicalizedResource如:/BucketName/ObjectName?acl&response-content-type=ContentType&uploadId=UploadId。 说明 OSS目前支持的子资源(sub-resource)包括:acl,uploads,location,cors,logging,website,referer,lifecycle,delete,append,tagging,objectMeta,uploadId,partNumber,security-token,position,img,style,styleName,replication,replicationProgress,replicationLocation,cname,bucketInfo,comp,qos,live,status,vod,startTime,endTime,symlink,x-oss-process,response-content-type,response-content-language,response-expires,response-cache-control,response-content-disposition,response-content-encoding等 子资源(sub-resource)有三种类型: 资源标识,如子资源中的acl,append,uploadId,symlink等,详见关于Bucket的操作和关于Object的操作。 指定返回Header字段,如 response-***,详见GetObject的Request Parameters。 文件(Object)处理方式,如 x-oss-process,用于文件的处理方式,如图片处理。 计算签名头规则 签名的字符串必须为 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就设置为空。 签名示例 假如AccessKeyId是”44CF9590006BF252F707”,AccessKeySecret是”OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV” 请求 签名字符串计算公式 签名字符串 PUT /nelson HTTP/1.0 Content-MD5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra Signature = base64(hmac-sha1(AccessKeySecret,VERB + “\n” + Content-MD5 + “\n”+ Content-Type + “\n” + Date + “\n” + CanonicalizedOSSHeaders+ CanonicalizedResource)) “PUT\n eB5eJF1ptWaXm4bijSPyxw==\n text/html\n Thu, 17 Nov 2005 18:49:58 GMT\n x-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nels 可用以下方法计算签名(Signature): python示例代码: import base64 import hmac import sha h = hmac.new("OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV", "PUT\nODBGOERFMDMzQTczRUY3NUE3NzA5QzdFNUYzMDQxNEM=\ntext/html\nThu, 17 Nov 2005 18:49:58 GMT\nx-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nelson", sha) Signature = base64.b64encode(h.digest()) print("Signature: %s" % Signature) 签名(Signature)计算结果应该为 26NBxoKdsyly4EDv6inkoDft/yA=,因为Authorization = “OSS “ + AccessKeyId + “:” + Signature所以最后Authorization为 “OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA=”然后加上Authorization头来组成最后需要发送的消息: PUT /nelson HTTP/1.0 Authorization:OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA= Content-Md5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra 细节分析 如果传入的AccessKeyId不存在或inactive,返回403 Forbidden。错误码:InvalidAccessKeyId。 若用户请求头中Authorization值的格式不对,返回400 Bad Request。错误码:InvalidArgument。 OSS所有的请求都必须使用HTTP 1.1协议规定的GMT时间格式。其中,日期的格式为:date1 = 2DIGIT SP month SP 4DIGIT; day month year (e.g., 02 Jun 1982)上述日期格式中,“天”所占位数都是“2 DIGIT”。因此,“Jun 2”、“2 Jun 1982”和“2-Jun-82”都是非法日期格式。 如果签名验证的时候,头中没有传入Date或者格式不正确,返回403 Forbidden错误。错误码:AccessDenied。 传入请求的时间必须在OSS服务器当前时间之后的15分钟以内,否则返回403 Forbidden。错误码:RequestTimeTooSkewed。 如果AccessKeyId是active的,但OSS判断用户的请求发生签名错误,则返回403 Forbidden,并在返回给用户的response中告诉用户正确的用于验证加密的签名字符串。用户可以根据OSS的response来检查自己的签名字符串是否正确。返回示例:<?xml version="1.0" ?> <Error> <Code> SignatureDoesNotMatch </Code> <Message> The request signature we calculated does not match the signature you provided. Check your key and signing method. </Message> <StringToSignBytes> 47 45 54 0a 0a 0a 57 65 64 2c 20 31 31 20 4d 61 79 20 32 30 31 31 20 30 37 3a 35 39 3a 32 35 20 47 4d 54 0a 2f 75 73 72 65 61 6c 74 65 73 74 3f 61 63 6c </StringToSignBytes> <RequestId> 1E446260FF9B10C2 </RequestId> <HostId> oss-cn-hangzhou.aliyuncs.com </HostId> <SignatureProvided> y5H7yzPsA/tP4+0tH1HHvPEwUv8= </SignatureProvided> <StringToSign> GET Wed, 11 May 2011 07:59:25 GMT /oss-example?acl </StringToSign> <OSSAccessKeyId> AKIAIVAKMSMOY7VOMRWQ </OSSAccessKeyId> </Error> 说明 OSS SDK已经实现签名,用户使用OSS SDK不需要关注签名问题。如果您想了解具体语言的签名实现,请参考OSS SDK的代码。OSS SDK签名实现的文件如下表: SDK 签名实现 Java SDK OSSRequestSigner.java Python SDK auth.py .Net SDK OssRequestSigner.cs PHP SDK OssClient.php C SDK oss_auth.c JavaScript SDK client.js Go SDK auth.go Ruby SDK util.rb iOS SDK OSSModel.m Android SDK OSSUtils.java 当您自己实现签名,访问OSS报 SignatureDoesNotMatch 错误时,请使用可视化签名工具确认签名并排除错误。 常见问题 Content-MD5的计算方法 Content-MD5的计算 以消息内容为"123456789"来说,计算这个字符串的Content-MD5 正确的计算方式: 标准中定义的算法简单点说就是: 1. 先计算MD5加密的二进制数组(128位)。 2. 再对这个二进制进行base64编码(而不是对32位字符串编码)。 以Python为例子: 正确计算的代码为: >>> import base64,hashlib >>> hash = hashlib.md5() >>> hash.update("0123456789") >>> base64.b64encode(hash.digest()) 'eB5eJF1ptWaXm4bijSPyxw==' 需要注意 正确的是:hash.digest(),计算出进制数组(128位) >>> hash.digest() 'x\x1e^$]i\xb5f\x97\x9b\x86\xe2\x8d#\xf2\xc7' 常见错误是直接对计算出的32位字符串编码进行base64编码。 例如,错误的是:hash.hexdigest(),计算得到可见的32位字符串编码 >>> hash.hexdigest() '781e5e245d69b566979b86e28d23f2c7' 错误的MD5值进行base64编码后的结果: >>> base64.b64encode(hash.hexdigest()) 'NzgxZTVlMjQ1ZDY5YjU2Njk3OWI4NmUyOGQyM2YyYzc='

2019-12-01 23:13:45 0 浏览量 回答数 0

试用中心

为您提供0门槛上云实践机会,企业用户最高免费12个月

回答

详细解答可以参考官方帮助文档 用户可以在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错误。 构建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中。此时的CanonicalizedResource如:/BucketName/ObjectName?acl&response-content-type=ContentType&uploadId=UploadId。 说明 OSS目前支持的子资源(sub-resource)包括:acl,uploads,location,cors,logging,website,referer,lifecycle,delete,append,tagging,objectMeta,uploadId,partNumber,security-token,position,img,style,styleName,replication,replicationProgress,replicationLocation,cname,bucketInfo,comp,qos,live,status,vod,startTime,endTime,symlink,x-oss-process,response-content-type,response-content-language,response-expires,response-cache-control,response-content-disposition,response-content-encoding等 子资源(sub-resource)有三种类型: 资源标识,如子资源中的acl,append,uploadId,symlink等,详见关于Bucket的操作和关于Object的操作。 指定返回Header字段,如 response-***,详见GetObject的Request Parameters。 文件(Object)处理方式,如 x-oss-process,用于文件的处理方式,如图片处理。 计算签名头规则 签名的字符串必须为 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就设置为空。 签名示例 假如AccessKeyId是”44CF9590006BF252F707”,AccessKeySecret是”OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV” 请求 签名字符串计算公式 签名字符串 PUT /nelson HTTP/1.0 Content-MD5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra Signature = base64(hmac-sha1(AccessKeySecret,VERB + “\n” + Content-MD5 + “\n”+ Content-Type + “\n” + Date + “\n” + CanonicalizedOSSHeaders+ CanonicalizedResource)) “PUT\n eB5eJF1ptWaXm4bijSPyxw==\n text/html\n Thu, 17 Nov 2005 18:49:58 GMT\n x-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nels 可用以下方法计算签名(Signature): python示例代码: import base64 import hmac import sha h = hmac.new("OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV", "PUT\nODBGOERFMDMzQTczRUY3NUE3NzA5QzdFNUYzMDQxNEM=\ntext/html\nThu, 17 Nov 2005 18:49:58 GMT\nx-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nelson", sha) Signature = base64.b64encode(h.digest()) print("Signature: %s" % Signature) 签名(Signature)计算结果应该为 26NBxoKdsyly4EDv6inkoDft/yA=,因为Authorization = “OSS “ + AccessKeyId + “:” + Signature所以最后Authorization为 “OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA=”然后加上Authorization头来组成最后需要发送的消息: PUT /nelson HTTP/1.0 Authorization:OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA= Content-Md5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra 细节分析 如果传入的AccessKeyId不存在或inactive,返回403 Forbidden。错误码:InvalidAccessKeyId。 若用户请求头中Authorization值的格式不对,返回400 Bad Request。错误码:InvalidArgument。 OSS所有的请求都必须使用HTTP 1.1协议规定的GMT时间格式。其中,日期的格式为:date1 = 2DIGIT SP month SP 4DIGIT; day month year (e.g., 02 Jun 1982)上述日期格式中,“天”所占位数都是“2 DIGIT”。因此,“Jun 2”、“2 Jun 1982”和“2-Jun-82”都是非法日期格式。 如果签名验证的时候,头中没有传入Date或者格式不正确,返回403 Forbidden错误。错误码:AccessDenied。 传入请求的时间必须在OSS服务器当前时间之后的15分钟以内,否则返回403 Forbidden。错误码:RequestTimeTooSkewed。 如果AccessKeyId是active的,但OSS判断用户的请求发生签名错误,则返回403 Forbidden,并在返回给用户的response中告诉用户正确的用于验证加密的签名字符串。用户可以根据OSS的response来检查自己的签名字符串是否正确。返回示例:<?xml version="1.0" ?> <Error> <Code> SignatureDoesNotMatch </Code> <Message> The request signature we calculated does not match the signature you provided. Check your key and signing method. </Message> <StringToSignBytes> 47 45 54 0a 0a 0a 57 65 64 2c 20 31 31 20 4d 61 79 20 32 30 31 31 20 30 37 3a 35 39 3a 32 35 20 47 4d 54 0a 2f 75 73 72 65 61 6c 74 65 73 74 3f 61 63 6c </StringToSignBytes> <RequestId> 1E446260FF9B10C2 </RequestId> <HostId> oss-cn-hangzhou.aliyuncs.com </HostId> <SignatureProvided> y5H7yzPsA/tP4+0tH1HHvPEwUv8= </SignatureProvided> <StringToSign> GET Wed, 11 May 2011 07:59:25 GMT /oss-example?acl </StringToSign> <OSSAccessKeyId> AKIAIVAKMSMOY7VOMRWQ </OSSAccessKeyId> </Error> 说明 OSS SDK已经实现签名,用户使用OSS SDK不需要关注签名问题。如果您想了解具体语言的签名实现,请参考OSS SDK的代码。OSS SDK签名实现的文件如下表: SDK 签名实现 Java SDK OSSRequestSigner.java Python SDK auth.py .Net SDK OssRequestSigner.cs PHP SDK OssClient.php C SDK oss_auth.c JavaScript SDK client.js Go SDK auth.go Ruby SDK util.rb iOS SDK OSSModel.m Android SDK OSSUtils.java 当您自己实现签名,访问OSS报 SignatureDoesNotMatch 错误时,请使用可视化签名工具确认签名并排除错误。 常见问题 Content-MD5的计算方法 Content-MD5的计算 以消息内容为"123456789"来说,计算这个字符串的Content-MD5 正确的计算方式: 标准中定义的算法简单点说就是: 1. 先计算MD5加密的二进制数组(128位)。 2. 再对这个二进制进行base64编码(而不是对32位字符串编码)。 以Python为例子: 正确计算的代码为: >>> import base64,hashlib >>> hash = hashlib.md5() >>> hash.update("0123456789") >>> base64.b64encode(hash.digest()) 'eB5eJF1ptWaXm4bijSPyxw==' 需要注意 正确的是:hash.digest(),计算出进制数组(128位) >>> hash.digest() 'x\x1e^$]i\xb5f\x97\x9b\x86\xe2\x8d#\xf2\xc7' 常见错误是直接对计算出的32位字符串编码进行base64编码。 例如,错误的是:hash.hexdigest(),计算得到可见的32位字符串编码 >>> hash.hexdigest() '781e5e245d69b566979b86e28d23f2c7' 错误的MD5值进行base64编码后的结果: >>> base64.b64encode(hash.hexdigest()) 'NzgxZTVlMjQ1ZDY5YjU2Njk3OWI4NmUyOGQyM2YyYzc='

2019-12-01 23:13:45 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 用户可以在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错误。 构建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中。此时的CanonicalizedResource如:/BucketName/ObjectName?acl&response-content-type=ContentType&uploadId=UploadId。 说明 OSS目前支持的子资源(sub-resource)包括:acl,uploads,location,cors,logging,website,referer,lifecycle,delete,append,tagging,objectMeta,uploadId,partNumber,security-token,position,img,style,styleName,replication,replicationProgress,replicationLocation,cname,bucketInfo,comp,qos,live,status,vod,startTime,endTime,symlink,x-oss-process,response-content-type,response-content-language,response-expires,response-cache-control,response-content-disposition,response-content-encoding等 子资源(sub-resource)有三种类型: 资源标识,如子资源中的acl,append,uploadId,symlink等,详见关于Bucket的操作和关于Object的操作。 指定返回Header字段,如 response-***,详见GetObject的Request Parameters。 文件(Object)处理方式,如 x-oss-process,用于文件的处理方式,如图片处理。 计算签名头规则 签名的字符串必须为 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就设置为空。 签名示例 假如AccessKeyId是”44CF9590006BF252F707”,AccessKeySecret是”OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV” 请求 签名字符串计算公式 签名字符串 PUT /nelson HTTP/1.0 Content-MD5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra Signature = base64(hmac-sha1(AccessKeySecret,VERB + “\n” + Content-MD5 + “\n”+ Content-Type + “\n” + Date + “\n” + CanonicalizedOSSHeaders+ CanonicalizedResource)) “PUT\n eB5eJF1ptWaXm4bijSPyxw==\n text/html\n Thu, 17 Nov 2005 18:49:58 GMT\n x-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nels 可用以下方法计算签名(Signature): python示例代码: import base64 import hmac import sha h = hmac.new("OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV", "PUT\nODBGOERFMDMzQTczRUY3NUE3NzA5QzdFNUYzMDQxNEM=\ntext/html\nThu, 17 Nov 2005 18:49:58 GMT\nx-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nelson", sha) Signature = base64.b64encode(h.digest()) print("Signature: %s" % Signature) 签名(Signature)计算结果应该为 26NBxoKdsyly4EDv6inkoDft/yA=,因为Authorization = “OSS “ + AccessKeyId + “:” + Signature所以最后Authorization为 “OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA=”然后加上Authorization头来组成最后需要发送的消息: PUT /nelson HTTP/1.0 Authorization:OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA= Content-Md5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra 细节分析 如果传入的AccessKeyId不存在或inactive,返回403 Forbidden。错误码:InvalidAccessKeyId。 若用户请求头中Authorization值的格式不对,返回400 Bad Request。错误码:InvalidArgument。 OSS所有的请求都必须使用HTTP 1.1协议规定的GMT时间格式。其中,日期的格式为:date1 = 2DIGIT SP month SP 4DIGIT; day month year (e.g., 02 Jun 1982)上述日期格式中,“天”所占位数都是“2 DIGIT”。因此,“Jun 2”、“2 Jun 1982”和“2-Jun-82”都是非法日期格式。 如果签名验证的时候,头中没有传入Date或者格式不正确,返回403 Forbidden错误。错误码:AccessDenied。 传入请求的时间必须在OSS服务器当前时间之后的15分钟以内,否则返回403 Forbidden。错误码:RequestTimeTooSkewed。 如果AccessKeyId是active的,但OSS判断用户的请求发生签名错误,则返回403 Forbidden,并在返回给用户的response中告诉用户正确的用于验证加密的签名字符串。用户可以根据OSS的response来检查自己的签名字符串是否正确。返回示例:<?xml version="1.0" ?> <Error> <Code> SignatureDoesNotMatch </Code> <Message> The request signature we calculated does not match the signature you provided. Check your key and signing method. </Message> <StringToSignBytes> 47 45 54 0a 0a 0a 57 65 64 2c 20 31 31 20 4d 61 79 20 32 30 31 31 20 30 37 3a 35 39 3a 32 35 20 47 4d 54 0a 2f 75 73 72 65 61 6c 74 65 73 74 3f 61 63 6c </StringToSignBytes> <RequestId> 1E446260FF9B10C2 </RequestId> <HostId> oss-cn-hangzhou.aliyuncs.com </HostId> <SignatureProvided> y5H7yzPsA/tP4+0tH1HHvPEwUv8= </SignatureProvided> <StringToSign> GET Wed, 11 May 2011 07:59:25 GMT /oss-example?acl </StringToSign> <OSSAccessKeyId> AKIAIVAKMSMOY7VOMRWQ </OSSAccessKeyId> </Error> 说明 OSS SDK已经实现签名,用户使用OSS SDK不需要关注签名问题。如果您想了解具体语言的签名实现,请参考OSS SDK的代码。OSS SDK签名实现的文件如下表: SDK 签名实现 Java SDK OSSRequestSigner.java Python SDK auth.py .Net SDK OssRequestSigner.cs PHP SDK OssClient.php C SDK oss_auth.c JavaScript SDK client.js Go SDK auth.go Ruby SDK util.rb iOS SDK OSSModel.m Android SDK OSSUtils.java 当您自己实现签名,访问OSS报 SignatureDoesNotMatch 错误时,请使用可视化签名工具确认签名并排除错误。 常见问题 Content-MD5的计算方法 Content-MD5的计算 以消息内容为"123456789"来说,计算这个字符串的Content-MD5 正确的计算方式: 标准中定义的算法简单点说就是: 1. 先计算MD5加密的二进制数组(128位)。 2. 再对这个二进制进行base64编码(而不是对32位字符串编码)。 以Python为例子: 正确计算的代码为: >>> import base64,hashlib >>> hash = hashlib.md5() >>> hash.update("0123456789") >>> base64.b64encode(hash.digest()) 'eB5eJF1ptWaXm4bijSPyxw==' 需要注意 正确的是:hash.digest(),计算出进制数组(128位) >>> hash.digest() 'x\x1e^$]i\xb5f\x97\x9b\x86\xe2\x8d#\xf2\xc7' 常见错误是直接对计算出的32位字符串编码进行base64编码。 例如,错误的是:hash.hexdigest(),计算得到可见的32位字符串编码 >>> hash.hexdigest() '781e5e245d69b566979b86e28d23f2c7' 错误的MD5值进行base64编码后的结果: >>> base64.b64encode(hash.hexdigest()) 'NzgxZTVlMjQ1ZDY5YjU2Njk3OWI4NmUyOGQyM2YyYzc='

2019-12-01 23:13:43 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 用户可以在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错误。 构建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中。此时的CanonicalizedResource如:/BucketName/ObjectName?acl&response-content-type=ContentType&uploadId=UploadId。 说明 OSS目前支持的子资源(sub-resource)包括:acl,uploads,location,cors,logging,website,referer,lifecycle,delete,append,tagging,objectMeta,uploadId,partNumber,security-token,position,img,style,styleName,replication,replicationProgress,replicationLocation,cname,bucketInfo,comp,qos,live,status,vod,startTime,endTime,symlink,x-oss-process,response-content-type,response-content-language,response-expires,response-cache-control,response-content-disposition,response-content-encoding等 子资源(sub-resource)有三种类型: 资源标识,如子资源中的acl,append,uploadId,symlink等,详见关于Bucket的操作和关于Object的操作。 指定返回Header字段,如 response-***,详见GetObject的Request Parameters。 文件(Object)处理方式,如 x-oss-process,用于文件的处理方式,如图片处理。 计算签名头规则 签名的字符串必须为 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就设置为空。 签名示例 假如AccessKeyId是”44CF9590006BF252F707”,AccessKeySecret是”OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV” 请求 签名字符串计算公式 签名字符串 PUT /nelson HTTP/1.0 Content-MD5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra Signature = base64(hmac-sha1(AccessKeySecret,VERB + “\n” + Content-MD5 + “\n”+ Content-Type + “\n” + Date + “\n” + CanonicalizedOSSHeaders+ CanonicalizedResource)) “PUT\n eB5eJF1ptWaXm4bijSPyxw==\n text/html\n Thu, 17 Nov 2005 18:49:58 GMT\n x-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nels 可用以下方法计算签名(Signature): python示例代码: import base64 import hmac import sha h = hmac.new("OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV", "PUT\nODBGOERFMDMzQTczRUY3NUE3NzA5QzdFNUYzMDQxNEM=\ntext/html\nThu, 17 Nov 2005 18:49:58 GMT\nx-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nelson", sha) Signature = base64.b64encode(h.digest()) print("Signature: %s" % Signature) 签名(Signature)计算结果应该为 26NBxoKdsyly4EDv6inkoDft/yA=,因为Authorization = “OSS “ + AccessKeyId + “:” + Signature所以最后Authorization为 “OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA=”然后加上Authorization头来组成最后需要发送的消息: PUT /nelson HTTP/1.0 Authorization:OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA= Content-Md5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra 细节分析 如果传入的AccessKeyId不存在或inactive,返回403 Forbidden。错误码:InvalidAccessKeyId。 若用户请求头中Authorization值的格式不对,返回400 Bad Request。错误码:InvalidArgument。 OSS所有的请求都必须使用HTTP 1.1协议规定的GMT时间格式。其中,日期的格式为:date1 = 2DIGIT SP month SP 4DIGIT; day month year (e.g., 02 Jun 1982)上述日期格式中,“天”所占位数都是“2 DIGIT”。因此,“Jun 2”、“2 Jun 1982”和“2-Jun-82”都是非法日期格式。 如果签名验证的时候,头中没有传入Date或者格式不正确,返回403 Forbidden错误。错误码:AccessDenied。 传入请求的时间必须在OSS服务器当前时间之后的15分钟以内,否则返回403 Forbidden。错误码:RequestTimeTooSkewed。 如果AccessKeyId是active的,但OSS判断用户的请求发生签名错误,则返回403 Forbidden,并在返回给用户的response中告诉用户正确的用于验证加密的签名字符串。用户可以根据OSS的response来检查自己的签名字符串是否正确。返回示例:<?xml version="1.0" ?> <Error> <Code> SignatureDoesNotMatch </Code> <Message> The request signature we calculated does not match the signature you provided. Check your key and signing method. </Message> <StringToSignBytes> 47 45 54 0a 0a 0a 57 65 64 2c 20 31 31 20 4d 61 79 20 32 30 31 31 20 30 37 3a 35 39 3a 32 35 20 47 4d 54 0a 2f 75 73 72 65 61 6c 74 65 73 74 3f 61 63 6c </StringToSignBytes> <RequestId> 1E446260FF9B10C2 </RequestId> <HostId> oss-cn-hangzhou.aliyuncs.com </HostId> <SignatureProvided> y5H7yzPsA/tP4+0tH1HHvPEwUv8= </SignatureProvided> <StringToSign> GET Wed, 11 May 2011 07:59:25 GMT /oss-example?acl </StringToSign> <OSSAccessKeyId> AKIAIVAKMSMOY7VOMRWQ </OSSAccessKeyId> </Error> 说明 OSS SDK已经实现签名,用户使用OSS SDK不需要关注签名问题。如果您想了解具体语言的签名实现,请参考OSS SDK的代码。OSS SDK签名实现的文件如下表: SDK 签名实现 Java SDK OSSRequestSigner.java Python SDK auth.py .Net SDK OssRequestSigner.cs PHP SDK OssClient.php C SDK oss_auth.c JavaScript SDK client.js Go SDK auth.go Ruby SDK util.rb iOS SDK OSSModel.m Android SDK OSSUtils.java 当您自己实现签名,访问OSS报 SignatureDoesNotMatch 错误时,请使用可视化签名工具确认签名并排除错误。 常见问题 Content-MD5的计算方法 Content-MD5的计算 以消息内容为"123456789"来说,计算这个字符串的Content-MD5 正确的计算方式: 标准中定义的算法简单点说就是: 1. 先计算MD5加密的二进制数组(128位)。 2. 再对这个二进制进行base64编码(而不是对32位字符串编码)。 以Python为例子: 正确计算的代码为: >>> import base64,hashlib >>> hash = hashlib.md5() >>> hash.update("0123456789") >>> base64.b64encode(hash.digest()) 'eB5eJF1ptWaXm4bijSPyxw==' 需要注意 正确的是:hash.digest(),计算出进制数组(128位) >>> hash.digest() 'x\x1e^$]i\xb5f\x97\x9b\x86\xe2\x8d#\xf2\xc7' 常见错误是直接对计算出的32位字符串编码进行base64编码。 例如,错误的是:hash.hexdigest(),计算得到可见的32位字符串编码 >>> hash.hexdigest() '781e5e245d69b566979b86e28d23f2c7' 错误的MD5值进行base64编码后的结果: >>> base64.b64encode(hash.hexdigest()) 'NzgxZTVlMjQ1ZDY5YjU2Njk3OWI4NmUyOGQyM2YyYzc='

2019-12-01 23:13:44 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 用户可以在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错误。 构建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中。此时的CanonicalizedResource如:/BucketName/ObjectName?acl&response-content-type=ContentType&uploadId=UploadId。 说明 OSS目前支持的子资源(sub-resource)包括:acl,uploads,location,cors,logging,website,referer,lifecycle,delete,append,tagging,objectMeta,uploadId,partNumber,security-token,position,img,style,styleName,replication,replicationProgress,replicationLocation,cname,bucketInfo,comp,qos,live,status,vod,startTime,endTime,symlink,x-oss-process,response-content-type,response-content-language,response-expires,response-cache-control,response-content-disposition,response-content-encoding等 子资源(sub-resource)有三种类型: 资源标识,如子资源中的acl,append,uploadId,symlink等,详见关于Bucket的操作和关于Object的操作。 指定返回Header字段,如 response-***,详见GetObject的Request Parameters。 文件(Object)处理方式,如 x-oss-process,用于文件的处理方式,如图片处理。 计算签名头规则 签名的字符串必须为 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就设置为空。 签名示例 假如AccessKeyId是”44CF9590006BF252F707”,AccessKeySecret是”OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV” 请求 签名字符串计算公式 签名字符串 PUT /nelson HTTP/1.0 Content-MD5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra Signature = base64(hmac-sha1(AccessKeySecret,VERB + “\n” + Content-MD5 + “\n”+ Content-Type + “\n” + Date + “\n” + CanonicalizedOSSHeaders+ CanonicalizedResource)) “PUT\n eB5eJF1ptWaXm4bijSPyxw==\n text/html\n Thu, 17 Nov 2005 18:49:58 GMT\n x-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nels 可用以下方法计算签名(Signature): python示例代码: import base64 import hmac import sha h = hmac.new("OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV", "PUT\nODBGOERFMDMzQTczRUY3NUE3NzA5QzdFNUYzMDQxNEM=\ntext/html\nThu, 17 Nov 2005 18:49:58 GMT\nx-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nelson", sha) Signature = base64.b64encode(h.digest()) print("Signature: %s" % Signature) 签名(Signature)计算结果应该为 26NBxoKdsyly4EDv6inkoDft/yA=,因为Authorization = “OSS “ + AccessKeyId + “:” + Signature所以最后Authorization为 “OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA=”然后加上Authorization头来组成最后需要发送的消息: PUT /nelson HTTP/1.0 Authorization:OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA= Content-Md5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra 细节分析 如果传入的AccessKeyId不存在或inactive,返回403 Forbidden。错误码:InvalidAccessKeyId。 若用户请求头中Authorization值的格式不对,返回400 Bad Request。错误码:InvalidArgument。 OSS所有的请求都必须使用HTTP 1.1协议规定的GMT时间格式。其中,日期的格式为:date1 = 2DIGIT SP month SP 4DIGIT; day month year (e.g., 02 Jun 1982)上述日期格式中,“天”所占位数都是“2 DIGIT”。因此,“Jun 2”、“2 Jun 1982”和“2-Jun-82”都是非法日期格式。 如果签名验证的时候,头中没有传入Date或者格式不正确,返回403 Forbidden错误。错误码:AccessDenied。 传入请求的时间必须在OSS服务器当前时间之后的15分钟以内,否则返回403 Forbidden。错误码:RequestTimeTooSkewed。 如果AccessKeyId是active的,但OSS判断用户的请求发生签名错误,则返回403 Forbidden,并在返回给用户的response中告诉用户正确的用于验证加密的签名字符串。用户可以根据OSS的response来检查自己的签名字符串是否正确。返回示例:<?xml version="1.0" ?> <Error> <Code> SignatureDoesNotMatch </Code> <Message> The request signature we calculated does not match the signature you provided. Check your key and signing method. </Message> <StringToSignBytes> 47 45 54 0a 0a 0a 57 65 64 2c 20 31 31 20 4d 61 79 20 32 30 31 31 20 30 37 3a 35 39 3a 32 35 20 47 4d 54 0a 2f 75 73 72 65 61 6c 74 65 73 74 3f 61 63 6c </StringToSignBytes> <RequestId> 1E446260FF9B10C2 </RequestId> <HostId> oss-cn-hangzhou.aliyuncs.com </HostId> <SignatureProvided> y5H7yzPsA/tP4+0tH1HHvPEwUv8= </SignatureProvided> <StringToSign> GET Wed, 11 May 2011 07:59:25 GMT /oss-example?acl </StringToSign> <OSSAccessKeyId> AKIAIVAKMSMOY7VOMRWQ </OSSAccessKeyId> </Error> 说明 OSS SDK已经实现签名,用户使用OSS SDK不需要关注签名问题。如果您想了解具体语言的签名实现,请参考OSS SDK的代码。OSS SDK签名实现的文件如下表: SDK 签名实现 Java SDK OSSRequestSigner.java Python SDK auth.py .Net SDK OssRequestSigner.cs PHP SDK OssClient.php C SDK oss_auth.c JavaScript SDK client.js Go SDK auth.go Ruby SDK util.rb iOS SDK OSSModel.m Android SDK OSSUtils.java 当您自己实现签名,访问OSS报 SignatureDoesNotMatch 错误时,请使用可视化签名工具确认签名并排除错误。 常见问题 Content-MD5的计算方法 Content-MD5的计算 以消息内容为"123456789"来说,计算这个字符串的Content-MD5 正确的计算方式: 标准中定义的算法简单点说就是: 1. 先计算MD5加密的二进制数组(128位)。 2. 再对这个二进制进行base64编码(而不是对32位字符串编码)。 以Python为例子: 正确计算的代码为: >>> import base64,hashlib >>> hash = hashlib.md5() >>> hash.update("0123456789") >>> base64.b64encode(hash.digest()) 'eB5eJF1ptWaXm4bijSPyxw==' 需要注意 正确的是:hash.digest(),计算出进制数组(128位) >>> hash.digest() 'x\x1e^$]i\xb5f\x97\x9b\x86\xe2\x8d#\xf2\xc7' 常见错误是直接对计算出的32位字符串编码进行base64编码。 例如,错误的是:hash.hexdigest(),计算得到可见的32位字符串编码 >>> hash.hexdigest() '781e5e245d69b566979b86e28d23f2c7' 错误的MD5值进行base64编码后的结果: >>> base64.b64encode(hash.hexdigest()) 'NzgxZTVlMjQ1ZDY5YjU2Njk3OWI4NmUyOGQyM2YyYzc='

2019-12-01 23:13:44 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 用户可以在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错误。 构建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中。此时的CanonicalizedResource如:/BucketName/ObjectName?acl&response-content-type=ContentType&uploadId=UploadId。 说明 OSS目前支持的子资源(sub-resource)包括:acl,uploads,location,cors,logging,website,referer,lifecycle,delete,append,tagging,objectMeta,uploadId,partNumber,security-token,position,img,style,styleName,replication,replicationProgress,replicationLocation,cname,bucketInfo,comp,qos,live,status,vod,startTime,endTime,symlink,x-oss-process,response-content-type,response-content-language,response-expires,response-cache-control,response-content-disposition,response-content-encoding等 子资源(sub-resource)有三种类型: 资源标识,如子资源中的acl,append,uploadId,symlink等,详见关于Bucket的操作和关于Object的操作。 指定返回Header字段,如 response-***,详见GetObject的Request Parameters。 文件(Object)处理方式,如 x-oss-process,用于文件的处理方式,如图片处理。 计算签名头规则 签名的字符串必须为 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就设置为空。 签名示例 假如AccessKeyId是”44CF9590006BF252F707”,AccessKeySecret是”OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV” 请求 签名字符串计算公式 签名字符串 PUT /nelson HTTP/1.0 Content-MD5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra Signature = base64(hmac-sha1(AccessKeySecret,VERB + “\n” + Content-MD5 + “\n”+ Content-Type + “\n” + Date + “\n” + CanonicalizedOSSHeaders+ CanonicalizedResource)) “PUT\n eB5eJF1ptWaXm4bijSPyxw==\n text/html\n Thu, 17 Nov 2005 18:49:58 GMT\n x-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nels 可用以下方法计算签名(Signature): python示例代码: import base64 import hmac import sha h = hmac.new("OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV", "PUT\nODBGOERFMDMzQTczRUY3NUE3NzA5QzdFNUYzMDQxNEM=\ntext/html\nThu, 17 Nov 2005 18:49:58 GMT\nx-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nelson", sha) Signature = base64.b64encode(h.digest()) print("Signature: %s" % Signature) 签名(Signature)计算结果应该为 26NBxoKdsyly4EDv6inkoDft/yA=,因为Authorization = “OSS “ + AccessKeyId + “:” + Signature所以最后Authorization为 “OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA=”然后加上Authorization头来组成最后需要发送的消息: PUT /nelson HTTP/1.0 Authorization:OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA= Content-Md5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra 细节分析 如果传入的AccessKeyId不存在或inactive,返回403 Forbidden。错误码:InvalidAccessKeyId。 若用户请求头中Authorization值的格式不对,返回400 Bad Request。错误码:InvalidArgument。 OSS所有的请求都必须使用HTTP 1.1协议规定的GMT时间格式。其中,日期的格式为:date1 = 2DIGIT SP month SP 4DIGIT; day month year (e.g., 02 Jun 1982)上述日期格式中,“天”所占位数都是“2 DIGIT”。因此,“Jun 2”、“2 Jun 1982”和“2-Jun-82”都是非法日期格式。 如果签名验证的时候,头中没有传入Date或者格式不正确,返回403 Forbidden错误。错误码:AccessDenied。 传入请求的时间必须在OSS服务器当前时间之后的15分钟以内,否则返回403 Forbidden。错误码:RequestTimeTooSkewed。 如果AccessKeyId是active的,但OSS判断用户的请求发生签名错误,则返回403 Forbidden,并在返回给用户的response中告诉用户正确的用于验证加密的签名字符串。用户可以根据OSS的response来检查自己的签名字符串是否正确。返回示例:<?xml version="1.0" ?> <Error> <Code> SignatureDoesNotMatch </Code> <Message> The request signature we calculated does not match the signature you provided. Check your key and signing method. </Message> <StringToSignBytes> 47 45 54 0a 0a 0a 57 65 64 2c 20 31 31 20 4d 61 79 20 32 30 31 31 20 30 37 3a 35 39 3a 32 35 20 47 4d 54 0a 2f 75 73 72 65 61 6c 74 65 73 74 3f 61 63 6c </StringToSignBytes> <RequestId> 1E446260FF9B10C2 </RequestId> <HostId> oss-cn-hangzhou.aliyuncs.com </HostId> <SignatureProvided> y5H7yzPsA/tP4+0tH1HHvPEwUv8= </SignatureProvided> <StringToSign> GET Wed, 11 May 2011 07:59:25 GMT /oss-example?acl </StringToSign> <OSSAccessKeyId> AKIAIVAKMSMOY7VOMRWQ </OSSAccessKeyId> </Error> 说明 OSS SDK已经实现签名,用户使用OSS SDK不需要关注签名问题。如果您想了解具体语言的签名实现,请参考OSS SDK的代码。OSS SDK签名实现的文件如下表: SDK 签名实现 Java SDK OSSRequestSigner.java Python SDK auth.py .Net SDK OssRequestSigner.cs PHP SDK OssClient.php C SDK oss_auth.c JavaScript SDK client.js Go SDK auth.go Ruby SDK util.rb iOS SDK OSSModel.m Android SDK OSSUtils.java 当您自己实现签名,访问OSS报 SignatureDoesNotMatch 错误时,请使用可视化签名工具确认签名并排除错误。 常见问题 Content-MD5的计算方法 Content-MD5的计算 以消息内容为"123456789"来说,计算这个字符串的Content-MD5 正确的计算方式: 标准中定义的算法简单点说就是: 1. 先计算MD5加密的二进制数组(128位)。 2. 再对这个二进制进行base64编码(而不是对32位字符串编码)。 以Python为例子: 正确计算的代码为: >>> import base64,hashlib >>> hash = hashlib.md5() >>> hash.update("0123456789") >>> base64.b64encode(hash.digest()) 'eB5eJF1ptWaXm4bijSPyxw==' 需要注意 正确的是:hash.digest(),计算出进制数组(128位) >>> hash.digest() 'x\x1e^$]i\xb5f\x97\x9b\x86\xe2\x8d#\xf2\xc7' 常见错误是直接对计算出的32位字符串编码进行base64编码。 例如,错误的是:hash.hexdigest(),计算得到可见的32位字符串编码 >>> hash.hexdigest() '781e5e245d69b566979b86e28d23f2c7' 错误的MD5值进行base64编码后的结果: >>> base64.b64encode(hash.hexdigest()) 'NzgxZTVlMjQ1ZDY5YjU2Njk3OWI4NmUyOGQyM2YyYzc='

2019-12-01 23:13:43 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 用户可以在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错误。 构建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中。此时的CanonicalizedResource如:/BucketName/ObjectName?acl&response-content-type=ContentType&uploadId=UploadId。 说明 OSS目前支持的子资源(sub-resource)包括:acl,uploads,location,cors,logging,website,referer,lifecycle,delete,append,tagging,objectMeta,uploadId,partNumber,security-token,position,img,style,styleName,replication,replicationProgress,replicationLocation,cname,bucketInfo,comp,qos,live,status,vod,startTime,endTime,symlink,x-oss-process,response-content-type,response-content-language,response-expires,response-cache-control,response-content-disposition,response-content-encoding等 子资源(sub-resource)有三种类型: 资源标识,如子资源中的acl,append,uploadId,symlink等,详见关于Bucket的操作和关于Object的操作。 指定返回Header字段,如 response-***,详见GetObject的Request Parameters。 文件(Object)处理方式,如 x-oss-process,用于文件的处理方式,如图片处理。 计算签名头规则 签名的字符串必须为 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就设置为空。 签名示例 假如AccessKeyId是”44CF9590006BF252F707”,AccessKeySecret是”OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV” 请求 签名字符串计算公式 签名字符串 PUT /nelson HTTP/1.0 Content-MD5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra Signature = base64(hmac-sha1(AccessKeySecret,VERB + “\n” + Content-MD5 + “\n”+ Content-Type + “\n” + Date + “\n” + CanonicalizedOSSHeaders+ CanonicalizedResource)) “PUT\n eB5eJF1ptWaXm4bijSPyxw==\n text/html\n Thu, 17 Nov 2005 18:49:58 GMT\n x-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nels 可用以下方法计算签名(Signature): python示例代码: import base64 import hmac import sha h = hmac.new("OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV", "PUT\nODBGOERFMDMzQTczRUY3NUE3NzA5QzdFNUYzMDQxNEM=\ntext/html\nThu, 17 Nov 2005 18:49:58 GMT\nx-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nelson", sha) Signature = base64.b64encode(h.digest()) print("Signature: %s" % Signature) 签名(Signature)计算结果应该为 26NBxoKdsyly4EDv6inkoDft/yA=,因为Authorization = “OSS “ + AccessKeyId + “:” + Signature所以最后Authorization为 “OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA=”然后加上Authorization头来组成最后需要发送的消息: PUT /nelson HTTP/1.0 Authorization:OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA= Content-Md5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra 细节分析 如果传入的AccessKeyId不存在或inactive,返回403 Forbidden。错误码:InvalidAccessKeyId。 若用户请求头中Authorization值的格式不对,返回400 Bad Request。错误码:InvalidArgument。 OSS所有的请求都必须使用HTTP 1.1协议规定的GMT时间格式。其中,日期的格式为:date1 = 2DIGIT SP month SP 4DIGIT; day month year (e.g., 02 Jun 1982)上述日期格式中,“天”所占位数都是“2 DIGIT”。因此,“Jun 2”、“2 Jun 1982”和“2-Jun-82”都是非法日期格式。 如果签名验证的时候,头中没有传入Date或者格式不正确,返回403 Forbidden错误。错误码:AccessDenied。 传入请求的时间必须在OSS服务器当前时间之后的15分钟以内,否则返回403 Forbidden。错误码:RequestTimeTooSkewed。 如果AccessKeyId是active的,但OSS判断用户的请求发生签名错误,则返回403 Forbidden,并在返回给用户的response中告诉用户正确的用于验证加密的签名字符串。用户可以根据OSS的response来检查自己的签名字符串是否正确。返回示例:<?xml version="1.0" ?> <Error> <Code> SignatureDoesNotMatch </Code> <Message> The request signature we calculated does not match the signature you provided. Check your key and signing method. </Message> <StringToSignBytes> 47 45 54 0a 0a 0a 57 65 64 2c 20 31 31 20 4d 61 79 20 32 30 31 31 20 30 37 3a 35 39 3a 32 35 20 47 4d 54 0a 2f 75 73 72 65 61 6c 74 65 73 74 3f 61 63 6c </StringToSignBytes> <RequestId> 1E446260FF9B10C2 </RequestId> <HostId> oss-cn-hangzhou.aliyuncs.com </HostId> <SignatureProvided> y5H7yzPsA/tP4+0tH1HHvPEwUv8= </SignatureProvided> <StringToSign> GET Wed, 11 May 2011 07:59:25 GMT /oss-example?acl </StringToSign> <OSSAccessKeyId> AKIAIVAKMSMOY7VOMRWQ </OSSAccessKeyId> </Error> 说明 OSS SDK已经实现签名,用户使用OSS SDK不需要关注签名问题。如果您想了解具体语言的签名实现,请参考OSS SDK的代码。OSS SDK签名实现的文件如下表: SDK 签名实现 Java SDK OSSRequestSigner.java Python SDK auth.py .Net SDK OssRequestSigner.cs PHP SDK OssClient.php C SDK oss_auth.c JavaScript SDK client.js Go SDK auth.go Ruby SDK util.rb iOS SDK OSSModel.m Android SDK OSSUtils.java 当您自己实现签名,访问OSS报 SignatureDoesNotMatch 错误时,请使用可视化签名工具确认签名并排除错误。 常见问题 Content-MD5的计算方法 Content-MD5的计算 以消息内容为"123456789"来说,计算这个字符串的Content-MD5 正确的计算方式: 标准中定义的算法简单点说就是: 1. 先计算MD5加密的二进制数组(128位)。 2. 再对这个二进制进行base64编码(而不是对32位字符串编码)。 以Python为例子: 正确计算的代码为: >>> import base64,hashlib >>> hash = hashlib.md5() >>> hash.update("0123456789") >>> base64.b64encode(hash.digest()) 'eB5eJF1ptWaXm4bijSPyxw==' 需要注意 正确的是:hash.digest(),计算出进制数组(128位) >>> hash.digest() 'x\x1e^$]i\xb5f\x97\x9b\x86\xe2\x8d#\xf2\xc7' 常见错误是直接对计算出的32位字符串编码进行base64编码。 例如,错误的是:hash.hexdigest(),计算得到可见的32位字符串编码 >>> hash.hexdigest() '781e5e245d69b566979b86e28d23f2c7' 错误的MD5值进行base64编码后的结果: >>> base64.b64encode(hash.hexdigest()) 'NzgxZTVlMjQ1ZDY5YjU2Njk3OWI4NmUyOGQyM2YyYzc='

2019-12-01 23:13:44 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 用户可以在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错误。 构建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中。此时的CanonicalizedResource如:/BucketName/ObjectName?acl&response-content-type=ContentType&uploadId=UploadId。 说明 OSS目前支持的子资源(sub-resource)包括:acl,uploads,location,cors,logging,website,referer,lifecycle,delete,append,tagging,objectMeta,uploadId,partNumber,security-token,position,img,style,styleName,replication,replicationProgress,replicationLocation,cname,bucketInfo,comp,qos,live,status,vod,startTime,endTime,symlink,x-oss-process,response-content-type,response-content-language,response-expires,response-cache-control,response-content-disposition,response-content-encoding等 子资源(sub-resource)有三种类型: 资源标识,如子资源中的acl,append,uploadId,symlink等,详见关于Bucket的操作和关于Object的操作。 指定返回Header字段,如 response-***,详见GetObject的Request Parameters。 文件(Object)处理方式,如 x-oss-process,用于文件的处理方式,如图片处理。 计算签名头规则 签名的字符串必须为 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就设置为空。 签名示例 假如AccessKeyId是”44CF9590006BF252F707”,AccessKeySecret是”OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV” 请求 签名字符串计算公式 签名字符串 PUT /nelson HTTP/1.0 Content-MD5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra Signature = base64(hmac-sha1(AccessKeySecret,VERB + “\n” + Content-MD5 + “\n”+ Content-Type + “\n” + Date + “\n” + CanonicalizedOSSHeaders+ CanonicalizedResource)) “PUT\n eB5eJF1ptWaXm4bijSPyxw==\n text/html\n Thu, 17 Nov 2005 18:49:58 GMT\n x-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nels 可用以下方法计算签名(Signature): python示例代码: import base64 import hmac import sha h = hmac.new("OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV", "PUT\nODBGOERFMDMzQTczRUY3NUE3NzA5QzdFNUYzMDQxNEM=\ntext/html\nThu, 17 Nov 2005 18:49:58 GMT\nx-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nelson", sha) Signature = base64.b64encode(h.digest()) print("Signature: %s" % Signature) 签名(Signature)计算结果应该为 26NBxoKdsyly4EDv6inkoDft/yA=,因为Authorization = “OSS “ + AccessKeyId + “:” + Signature所以最后Authorization为 “OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA=”然后加上Authorization头来组成最后需要发送的消息: PUT /nelson HTTP/1.0 Authorization:OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA= Content-Md5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra 细节分析 如果传入的AccessKeyId不存在或inactive,返回403 Forbidden。错误码:InvalidAccessKeyId。 若用户请求头中Authorization值的格式不对,返回400 Bad Request。错误码:InvalidArgument。 OSS所有的请求都必须使用HTTP 1.1协议规定的GMT时间格式。其中,日期的格式为:date1 = 2DIGIT SP month SP 4DIGIT; day month year (e.g., 02 Jun 1982)上述日期格式中,“天”所占位数都是“2 DIGIT”。因此,“Jun 2”、“2 Jun 1982”和“2-Jun-82”都是非法日期格式。 如果签名验证的时候,头中没有传入Date或者格式不正确,返回403 Forbidden错误。错误码:AccessDenied。 传入请求的时间必须在OSS服务器当前时间之后的15分钟以内,否则返回403 Forbidden。错误码:RequestTimeTooSkewed。 如果AccessKeyId是active的,但OSS判断用户的请求发生签名错误,则返回403 Forbidden,并在返回给用户的response中告诉用户正确的用于验证加密的签名字符串。用户可以根据OSS的response来检查自己的签名字符串是否正确。返回示例:<?xml version="1.0" ?> <Error> <Code> SignatureDoesNotMatch </Code> <Message> The request signature we calculated does not match the signature you provided. Check your key and signing method. </Message> <StringToSignBytes> 47 45 54 0a 0a 0a 57 65 64 2c 20 31 31 20 4d 61 79 20 32 30 31 31 20 30 37 3a 35 39 3a 32 35 20 47 4d 54 0a 2f 75 73 72 65 61 6c 74 65 73 74 3f 61 63 6c </StringToSignBytes> <RequestId> 1E446260FF9B10C2 </RequestId> <HostId> oss-cn-hangzhou.aliyuncs.com </HostId> <SignatureProvided> y5H7yzPsA/tP4+0tH1HHvPEwUv8= </SignatureProvided> <StringToSign> GET Wed, 11 May 2011 07:59:25 GMT /oss-example?acl </StringToSign> <OSSAccessKeyId> AKIAIVAKMSMOY7VOMRWQ </OSSAccessKeyId> </Error> 说明 OSS SDK已经实现签名,用户使用OSS SDK不需要关注签名问题。如果您想了解具体语言的签名实现,请参考OSS SDK的代码。OSS SDK签名实现的文件如下表: SDK 签名实现 Java SDK OSSRequestSigner.java Python SDK auth.py .Net SDK OssRequestSigner.cs PHP SDK OssClient.php C SDK oss_auth.c JavaScript SDK client.js Go SDK auth.go Ruby SDK util.rb iOS SDK OSSModel.m Android SDK OSSUtils.java 当您自己实现签名,访问OSS报 SignatureDoesNotMatch 错误时,请使用可视化签名工具确认签名并排除错误。 常见问题 Content-MD5的计算方法 Content-MD5的计算 以消息内容为"123456789"来说,计算这个字符串的Content-MD5 正确的计算方式: 标准中定义的算法简单点说就是: 1. 先计算MD5加密的二进制数组(128位)。 2. 再对这个二进制进行base64编码(而不是对32位字符串编码)。 以Python为例子: 正确计算的代码为: >>> import base64,hashlib >>> hash = hashlib.md5() >>> hash.update("0123456789") >>> base64.b64encode(hash.digest()) 'eB5eJF1ptWaXm4bijSPyxw==' 需要注意 正确的是:hash.digest(),计算出进制数组(128位) >>> hash.digest() 'x\x1e^$]i\xb5f\x97\x9b\x86\xe2\x8d#\xf2\xc7' 常见错误是直接对计算出的32位字符串编码进行base64编码。 例如,错误的是:hash.hexdigest(),计算得到可见的32位字符串编码 >>> hash.hexdigest() '781e5e245d69b566979b86e28d23f2c7' 错误的MD5值进行base64编码后的结果: >>> base64.b64encode(hash.hexdigest()) 'NzgxZTVlMjQ1ZDY5YjU2Njk3OWI4NmUyOGQyM2YyYzc='

2019-12-01 23:13:44 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 用户可以在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错误。 构建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中。此时的CanonicalizedResource如:/BucketName/ObjectName?acl&response-content-type=ContentType&uploadId=UploadId。 说明 OSS目前支持的子资源(sub-resource)包括:acl,uploads,location,cors,logging,website,referer,lifecycle,delete,append,tagging,objectMeta,uploadId,partNumber,security-token,position,img,style,styleName,replication,replicationProgress,replicationLocation,cname,bucketInfo,comp,qos,live,status,vod,startTime,endTime,symlink,x-oss-process,response-content-type,response-content-language,response-expires,response-cache-control,response-content-disposition,response-content-encoding等 子资源(sub-resource)有三种类型: 资源标识,如子资源中的acl,append,uploadId,symlink等,详见关于Bucket的操作和关于Object的操作。 指定返回Header字段,如 response-***,详见GetObject的Request Parameters。 文件(Object)处理方式,如 x-oss-process,用于文件的处理方式,如图片处理。 计算签名头规则 签名的字符串必须为 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就设置为空。 签名示例 假如AccessKeyId是”44CF9590006BF252F707”,AccessKeySecret是”OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV” 请求 签名字符串计算公式 签名字符串 PUT /nelson HTTP/1.0 Content-MD5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra Signature = base64(hmac-sha1(AccessKeySecret,VERB + “\n” + Content-MD5 + “\n”+ Content-Type + “\n” + Date + “\n” + CanonicalizedOSSHeaders+ CanonicalizedResource)) “PUT\n eB5eJF1ptWaXm4bijSPyxw==\n text/html\n Thu, 17 Nov 2005 18:49:58 GMT\n x-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nels 可用以下方法计算签名(Signature): python示例代码: import base64 import hmac import sha h = hmac.new("OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV", "PUT\nODBGOERFMDMzQTczRUY3NUE3NzA5QzdFNUYzMDQxNEM=\ntext/html\nThu, 17 Nov 2005 18:49:58 GMT\nx-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nelson", sha) Signature = base64.b64encode(h.digest()) print("Signature: %s" % Signature) 签名(Signature)计算结果应该为 26NBxoKdsyly4EDv6inkoDft/yA=,因为Authorization = “OSS “ + AccessKeyId + “:” + Signature所以最后Authorization为 “OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA=”然后加上Authorization头来组成最后需要发送的消息: PUT /nelson HTTP/1.0 Authorization:OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA= Content-Md5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra 细节分析 如果传入的AccessKeyId不存在或inactive,返回403 Forbidden。错误码:InvalidAccessKeyId。 若用户请求头中Authorization值的格式不对,返回400 Bad Request。错误码:InvalidArgument。 OSS所有的请求都必须使用HTTP 1.1协议规定的GMT时间格式。其中,日期的格式为:date1 = 2DIGIT SP month SP 4DIGIT; day month year (e.g., 02 Jun 1982)上述日期格式中,“天”所占位数都是“2 DIGIT”。因此,“Jun 2”、“2 Jun 1982”和“2-Jun-82”都是非法日期格式。 如果签名验证的时候,头中没有传入Date或者格式不正确,返回403 Forbidden错误。错误码:AccessDenied。 传入请求的时间必须在OSS服务器当前时间之后的15分钟以内,否则返回403 Forbidden。错误码:RequestTimeTooSkewed。 如果AccessKeyId是active的,但OSS判断用户的请求发生签名错误,则返回403 Forbidden,并在返回给用户的response中告诉用户正确的用于验证加密的签名字符串。用户可以根据OSS的response来检查自己的签名字符串是否正确。返回示例:<?xml version="1.0" ?> <Error> <Code> SignatureDoesNotMatch </Code> <Message> The request signature we calculated does not match the signature you provided. Check your key and signing method. </Message> <StringToSignBytes> 47 45 54 0a 0a 0a 57 65 64 2c 20 31 31 20 4d 61 79 20 32 30 31 31 20 30 37 3a 35 39 3a 32 35 20 47 4d 54 0a 2f 75 73 72 65 61 6c 74 65 73 74 3f 61 63 6c </StringToSignBytes> <RequestId> 1E446260FF9B10C2 </RequestId> <HostId> oss-cn-hangzhou.aliyuncs.com </HostId> <SignatureProvided> y5H7yzPsA/tP4+0tH1HHvPEwUv8= </SignatureProvided> <StringToSign> GET Wed, 11 May 2011 07:59:25 GMT /oss-example?acl </StringToSign> <OSSAccessKeyId> AKIAIVAKMSMOY7VOMRWQ </OSSAccessKeyId> </Error> 说明 OSS SDK已经实现签名,用户使用OSS SDK不需要关注签名问题。如果您想了解具体语言的签名实现,请参考OSS SDK的代码。OSS SDK签名实现的文件如下表: SDK 签名实现 Java SDK OSSRequestSigner.java Python SDK auth.py .Net SDK OssRequestSigner.cs PHP SDK OssClient.php C SDK oss_auth.c JavaScript SDK client.js Go SDK auth.go Ruby SDK util.rb iOS SDK OSSModel.m Android SDK OSSUtils.java 当您自己实现签名,访问OSS报 SignatureDoesNotMatch 错误时,请使用可视化签名工具确认签名并排除错误。 常见问题 Content-MD5的计算方法 Content-MD5的计算 以消息内容为"123456789"来说,计算这个字符串的Content-MD5 正确的计算方式: 标准中定义的算法简单点说就是: 1. 先计算MD5加密的二进制数组(128位)。 2. 再对这个二进制进行base64编码(而不是对32位字符串编码)。 以Python为例子: 正确计算的代码为: >>> import base64,hashlib >>> hash = hashlib.md5() >>> hash.update("0123456789") >>> base64.b64encode(hash.digest()) 'eB5eJF1ptWaXm4bijSPyxw==' 需要注意 正确的是:hash.digest(),计算出进制数组(128位) >>> hash.digest() 'x\x1e^$]i\xb5f\x97\x9b\x86\xe2\x8d#\xf2\xc7' 常见错误是直接对计算出的32位字符串编码进行base64编码。 例如,错误的是:hash.hexdigest(),计算得到可见的32位字符串编码 >>> hash.hexdigest() '781e5e245d69b566979b86e28d23f2c7' 错误的MD5值进行base64编码后的结果: >>> base64.b64encode(hash.hexdigest()) 'NzgxZTVlMjQ1ZDY5YjU2Njk3OWI4NmUyOGQyM2YyYzc='

2019-12-01 23:13:45 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 用户可以在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错误。 构建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中。此时的CanonicalizedResource如:/BucketName/ObjectName?acl&response-content-type=ContentType&uploadId=UploadId。 说明 OSS目前支持的子资源(sub-resource)包括:acl,uploads,location,cors,logging,website,referer,lifecycle,delete,append,tagging,objectMeta,uploadId,partNumber,security-token,position,img,style,styleName,replication,replicationProgress,replicationLocation,cname,bucketInfo,comp,qos,live,status,vod,startTime,endTime,symlink,x-oss-process,response-content-type,response-content-language,response-expires,response-cache-control,response-content-disposition,response-content-encoding等 子资源(sub-resource)有三种类型: 资源标识,如子资源中的acl,append,uploadId,symlink等,详见关于Bucket的操作和关于Object的操作。 指定返回Header字段,如 response-***,详见GetObject的Request Parameters。 文件(Object)处理方式,如 x-oss-process,用于文件的处理方式,如图片处理。 计算签名头规则 签名的字符串必须为 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就设置为空。 签名示例 假如AccessKeyId是”44CF9590006BF252F707”,AccessKeySecret是”OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV” 请求 签名字符串计算公式 签名字符串 PUT /nelson HTTP/1.0 Content-MD5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra Signature = base64(hmac-sha1(AccessKeySecret,VERB + “\n” + Content-MD5 + “\n”+ Content-Type + “\n” + Date + “\n” + CanonicalizedOSSHeaders+ CanonicalizedResource)) “PUT\n eB5eJF1ptWaXm4bijSPyxw==\n text/html\n Thu, 17 Nov 2005 18:49:58 GMT\n x-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nels 可用以下方法计算签名(Signature): python示例代码: import base64 import hmac import sha h = hmac.new("OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV", "PUT\nODBGOERFMDMzQTczRUY3NUE3NzA5QzdFNUYzMDQxNEM=\ntext/html\nThu, 17 Nov 2005 18:49:58 GMT\nx-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nelson", sha) Signature = base64.b64encode(h.digest()) print("Signature: %s" % Signature) 签名(Signature)计算结果应该为 26NBxoKdsyly4EDv6inkoDft/yA=,因为Authorization = “OSS “ + AccessKeyId + “:” + Signature所以最后Authorization为 “OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA=”然后加上Authorization头来组成最后需要发送的消息: PUT /nelson HTTP/1.0 Authorization:OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA= Content-Md5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra 细节分析 如果传入的AccessKeyId不存在或inactive,返回403 Forbidden。错误码:InvalidAccessKeyId。 若用户请求头中Authorization值的格式不对,返回400 Bad Request。错误码:InvalidArgument。 OSS所有的请求都必须使用HTTP 1.1协议规定的GMT时间格式。其中,日期的格式为:date1 = 2DIGIT SP month SP 4DIGIT; day month year (e.g., 02 Jun 1982)上述日期格式中,“天”所占位数都是“2 DIGIT”。因此,“Jun 2”、“2 Jun 1982”和“2-Jun-82”都是非法日期格式。 如果签名验证的时候,头中没有传入Date或者格式不正确,返回403 Forbidden错误。错误码:AccessDenied。 传入请求的时间必须在OSS服务器当前时间之后的15分钟以内,否则返回403 Forbidden。错误码:RequestTimeTooSkewed。 如果AccessKeyId是active的,但OSS判断用户的请求发生签名错误,则返回403 Forbidden,并在返回给用户的response中告诉用户正确的用于验证加密的签名字符串。用户可以根据OSS的response来检查自己的签名字符串是否正确。返回示例:<?xml version="1.0" ?> <Error> <Code> SignatureDoesNotMatch </Code> <Message> The request signature we calculated does not match the signature you provided. Check your key and signing method. </Message> <StringToSignBytes> 47 45 54 0a 0a 0a 57 65 64 2c 20 31 31 20 4d 61 79 20 32 30 31 31 20 30 37 3a 35 39 3a 32 35 20 47 4d 54 0a 2f 75 73 72 65 61 6c 74 65 73 74 3f 61 63 6c </StringToSignBytes> <RequestId> 1E446260FF9B10C2 </RequestId> <HostId> oss-cn-hangzhou.aliyuncs.com </HostId> <SignatureProvided> y5H7yzPsA/tP4+0tH1HHvPEwUv8= </SignatureProvided> <StringToSign> GET Wed, 11 May 2011 07:59:25 GMT /oss-example?acl </StringToSign> <OSSAccessKeyId> AKIAIVAKMSMOY7VOMRWQ </OSSAccessKeyId> </Error> 说明 OSS SDK已经实现签名,用户使用OSS SDK不需要关注签名问题。如果您想了解具体语言的签名实现,请参考OSS SDK的代码。OSS SDK签名实现的文件如下表: SDK 签名实现 Java SDK OSSRequestSigner.java Python SDK auth.py .Net SDK OssRequestSigner.cs PHP SDK OssClient.php C SDK oss_auth.c JavaScript SDK client.js Go SDK auth.go Ruby SDK util.rb iOS SDK OSSModel.m Android SDK OSSUtils.java 当您自己实现签名,访问OSS报 SignatureDoesNotMatch 错误时,请使用可视化签名工具确认签名并排除错误。 常见问题 Content-MD5的计算方法 Content-MD5的计算 以消息内容为"123456789"来说,计算这个字符串的Content-MD5 正确的计算方式: 标准中定义的算法简单点说就是: 1. 先计算MD5加密的二进制数组(128位)。 2. 再对这个二进制进行base64编码(而不是对32位字符串编码)。 以Python为例子: 正确计算的代码为: >>> import base64,hashlib >>> hash = hashlib.md5() >>> hash.update("0123456789") >>> base64.b64encode(hash.digest()) 'eB5eJF1ptWaXm4bijSPyxw==' 需要注意 正确的是:hash.digest(),计算出进制数组(128位) >>> hash.digest() 'x\x1e^$]i\xb5f\x97\x9b\x86\xe2\x8d#\xf2\xc7' 常见错误是直接对计算出的32位字符串编码进行base64编码。 例如,错误的是:hash.hexdigest(),计算得到可见的32位字符串编码 >>> hash.hexdigest() '781e5e245d69b566979b86e28d23f2c7' 错误的MD5值进行base64编码后的结果: >>> base64.b64encode(hash.hexdigest()) 'NzgxZTVlMjQ1ZDY5YjU2Njk3OWI4NmUyOGQyM2YyYzc='

2019-12-01 23:13:44 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 用户可以在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错误。 构建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中。此时的CanonicalizedResource如:/BucketName/ObjectName?acl&response-content-type=ContentType&uploadId=UploadId。 说明 OSS目前支持的子资源(sub-resource)包括:acl,uploads,location,cors,logging,website,referer,lifecycle,delete,append,tagging,objectMeta,uploadId,partNumber,security-token,position,img,style,styleName,replication,replicationProgress,replicationLocation,cname,bucketInfo,comp,qos,live,status,vod,startTime,endTime,symlink,x-oss-process,response-content-type,response-content-language,response-expires,response-cache-control,response-content-disposition,response-content-encoding等 子资源(sub-resource)有三种类型: 资源标识,如子资源中的acl,append,uploadId,symlink等,详见关于Bucket的操作和关于Object的操作。 指定返回Header字段,如 response-***,详见GetObject的Request Parameters。 文件(Object)处理方式,如 x-oss-process,用于文件的处理方式,如图片处理。 计算签名头规则 签名的字符串必须为 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就设置为空。 签名示例 假如AccessKeyId是”44CF9590006BF252F707”,AccessKeySecret是”OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV” 请求 签名字符串计算公式 签名字符串 PUT /nelson HTTP/1.0 Content-MD5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra Signature = base64(hmac-sha1(AccessKeySecret,VERB + “\n” + Content-MD5 + “\n”+ Content-Type + “\n” + Date + “\n” + CanonicalizedOSSHeaders+ CanonicalizedResource)) “PUT\n eB5eJF1ptWaXm4bijSPyxw==\n text/html\n Thu, 17 Nov 2005 18:49:58 GMT\n x-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nels 可用以下方法计算签名(Signature): python示例代码: import base64 import hmac import sha h = hmac.new("OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV", "PUT\nODBGOERFMDMzQTczRUY3NUE3NzA5QzdFNUYzMDQxNEM=\ntext/html\nThu, 17 Nov 2005 18:49:58 GMT\nx-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nelson", sha) Signature = base64.b64encode(h.digest()) print("Signature: %s" % Signature) 签名(Signature)计算结果应该为 26NBxoKdsyly4EDv6inkoDft/yA=,因为Authorization = “OSS “ + AccessKeyId + “:” + Signature所以最后Authorization为 “OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA=”然后加上Authorization头来组成最后需要发送的消息: PUT /nelson HTTP/1.0 Authorization:OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA= Content-Md5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra 细节分析 如果传入的AccessKeyId不存在或inactive,返回403 Forbidden。错误码:InvalidAccessKeyId。 若用户请求头中Authorization值的格式不对,返回400 Bad Request。错误码:InvalidArgument。 OSS所有的请求都必须使用HTTP 1.1协议规定的GMT时间格式。其中,日期的格式为:date1 = 2DIGIT SP month SP 4DIGIT; day month year (e.g., 02 Jun 1982)上述日期格式中,“天”所占位数都是“2 DIGIT”。因此,“Jun 2”、“2 Jun 1982”和“2-Jun-82”都是非法日期格式。 如果签名验证的时候,头中没有传入Date或者格式不正确,返回403 Forbidden错误。错误码:AccessDenied。 传入请求的时间必须在OSS服务器当前时间之后的15分钟以内,否则返回403 Forbidden。错误码:RequestTimeTooSkewed。 如果AccessKeyId是active的,但OSS判断用户的请求发生签名错误,则返回403 Forbidden,并在返回给用户的response中告诉用户正确的用于验证加密的签名字符串。用户可以根据OSS的response来检查自己的签名字符串是否正确。返回示例:<?xml version="1.0" ?> <Error> <Code> SignatureDoesNotMatch </Code> <Message> The request signature we calculated does not match the signature you provided. Check your key and signing method. </Message> <StringToSignBytes> 47 45 54 0a 0a 0a 57 65 64 2c 20 31 31 20 4d 61 79 20 32 30 31 31 20 30 37 3a 35 39 3a 32 35 20 47 4d 54 0a 2f 75 73 72 65 61 6c 74 65 73 74 3f 61 63 6c </StringToSignBytes> <RequestId> 1E446260FF9B10C2 </RequestId> <HostId> oss-cn-hangzhou.aliyuncs.com </HostId> <SignatureProvided> y5H7yzPsA/tP4+0tH1HHvPEwUv8= </SignatureProvided> <StringToSign> GET Wed, 11 May 2011 07:59:25 GMT /oss-example?acl </StringToSign> <OSSAccessKeyId> AKIAIVAKMSMOY7VOMRWQ </OSSAccessKeyId> </Error> 说明 OSS SDK已经实现签名,用户使用OSS SDK不需要关注签名问题。如果您想了解具体语言的签名实现,请参考OSS SDK的代码。OSS SDK签名实现的文件如下表: SDK 签名实现 Java SDK OSSRequestSigner.java Python SDK auth.py .Net SDK OssRequestSigner.cs PHP SDK OssClient.php C SDK oss_auth.c JavaScript SDK client.js Go SDK auth.go Ruby SDK util.rb iOS SDK OSSModel.m Android SDK OSSUtils.java 当您自己实现签名,访问OSS报 SignatureDoesNotMatch 错误时,请使用可视化签名工具确认签名并排除错误。 常见问题 Content-MD5的计算方法 Content-MD5的计算 以消息内容为"123456789"来说,计算这个字符串的Content-MD5 正确的计算方式: 标准中定义的算法简单点说就是: 1. 先计算MD5加密的二进制数组(128位)。 2. 再对这个二进制进行base64编码(而不是对32位字符串编码)。 以Python为例子: 正确计算的代码为: >>> import base64,hashlib >>> hash = hashlib.md5() >>> hash.update("0123456789") >>> base64.b64encode(hash.digest()) 'eB5eJF1ptWaXm4bijSPyxw==' 需要注意 正确的是:hash.digest(),计算出进制数组(128位) >>> hash.digest() 'x\x1e^$]i\xb5f\x97\x9b\x86\xe2\x8d#\xf2\xc7' 常见错误是直接对计算出的32位字符串编码进行base64编码。 例如,错误的是:hash.hexdigest(),计算得到可见的32位字符串编码 >>> hash.hexdigest() '781e5e245d69b566979b86e28d23f2c7' 错误的MD5值进行base64编码后的结果: >>> base64.b64encode(hash.hexdigest()) 'NzgxZTVlMjQ1ZDY5YjU2Njk3OWI4NmUyOGQyM2YyYzc='

2019-12-01 23:13:43 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 用户可以在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错误。 构建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中。此时的CanonicalizedResource如:/BucketName/ObjectName?acl&response-content-type=ContentType&uploadId=UploadId。 说明 OSS目前支持的子资源(sub-resource)包括:acl,uploads,location,cors,logging,website,referer,lifecycle,delete,append,tagging,objectMeta,uploadId,partNumber,security-token,position,img,style,styleName,replication,replicationProgress,replicationLocation,cname,bucketInfo,comp,qos,live,status,vod,startTime,endTime,symlink,x-oss-process,response-content-type,response-content-language,response-expires,response-cache-control,response-content-disposition,response-content-encoding等 子资源(sub-resource)有三种类型: 资源标识,如子资源中的acl,append,uploadId,symlink等,详见关于Bucket的操作和关于Object的操作。 指定返回Header字段,如 response-***,详见GetObject的Request Parameters。 文件(Object)处理方式,如 x-oss-process,用于文件的处理方式,如图片处理。 计算签名头规则 签名的字符串必须为 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就设置为空。 签名示例 假如AccessKeyId是”44CF9590006BF252F707”,AccessKeySecret是”OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV” 请求 签名字符串计算公式 签名字符串 PUT /nelson HTTP/1.0 Content-MD5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra Signature = base64(hmac-sha1(AccessKeySecret,VERB + “\n” + Content-MD5 + “\n”+ Content-Type + “\n” + Date + “\n” + CanonicalizedOSSHeaders+ CanonicalizedResource)) “PUT\n eB5eJF1ptWaXm4bijSPyxw==\n text/html\n Thu, 17 Nov 2005 18:49:58 GMT\n x-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nels 可用以下方法计算签名(Signature): python示例代码: import base64 import hmac import sha h = hmac.new("OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV", "PUT\nODBGOERFMDMzQTczRUY3NUE3NzA5QzdFNUYzMDQxNEM=\ntext/html\nThu, 17 Nov 2005 18:49:58 GMT\nx-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nelson", sha) Signature = base64.b64encode(h.digest()) print("Signature: %s" % Signature) 签名(Signature)计算结果应该为 26NBxoKdsyly4EDv6inkoDft/yA=,因为Authorization = “OSS “ + AccessKeyId + “:” + Signature所以最后Authorization为 “OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA=”然后加上Authorization头来组成最后需要发送的消息: PUT /nelson HTTP/1.0 Authorization:OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA= Content-Md5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra 细节分析 如果传入的AccessKeyId不存在或inactive,返回403 Forbidden。错误码:InvalidAccessKeyId。 若用户请求头中Authorization值的格式不对,返回400 Bad Request。错误码:InvalidArgument。 OSS所有的请求都必须使用HTTP 1.1协议规定的GMT时间格式。其中,日期的格式为:date1 = 2DIGIT SP month SP 4DIGIT; day month year (e.g., 02 Jun 1982)上述日期格式中,“天”所占位数都是“2 DIGIT”。因此,“Jun 2”、“2 Jun 1982”和“2-Jun-82”都是非法日期格式。 如果签名验证的时候,头中没有传入Date或者格式不正确,返回403 Forbidden错误。错误码:AccessDenied。 传入请求的时间必须在OSS服务器当前时间之后的15分钟以内,否则返回403 Forbidden。错误码:RequestTimeTooSkewed。 如果AccessKeyId是active的,但OSS判断用户的请求发生签名错误,则返回403 Forbidden,并在返回给用户的response中告诉用户正确的用于验证加密的签名字符串。用户可以根据OSS的response来检查自己的签名字符串是否正确。返回示例:<?xml version="1.0" ?> <Error> <Code> SignatureDoesNotMatch </Code> <Message> The request signature we calculated does not match the signature you provided. Check your key and signing method. </Message> <StringToSignBytes> 47 45 54 0a 0a 0a 57 65 64 2c 20 31 31 20 4d 61 79 20 32 30 31 31 20 30 37 3a 35 39 3a 32 35 20 47 4d 54 0a 2f 75 73 72 65 61 6c 74 65 73 74 3f 61 63 6c </StringToSignBytes> <RequestId> 1E446260FF9B10C2 </RequestId> <HostId> oss-cn-hangzhou.aliyuncs.com </HostId> <SignatureProvided> y5H7yzPsA/tP4+0tH1HHvPEwUv8= </SignatureProvided> <StringToSign> GET Wed, 11 May 2011 07:59:25 GMT /oss-example?acl </StringToSign> <OSSAccessKeyId> AKIAIVAKMSMOY7VOMRWQ </OSSAccessKeyId> </Error> 说明 OSS SDK已经实现签名,用户使用OSS SDK不需要关注签名问题。如果您想了解具体语言的签名实现,请参考OSS SDK的代码。OSS SDK签名实现的文件如下表: SDK 签名实现 Java SDK OSSRequestSigner.java Python SDK auth.py .Net SDK OssRequestSigner.cs PHP SDK OssClient.php C SDK oss_auth.c JavaScript SDK client.js Go SDK auth.go Ruby SDK util.rb iOS SDK OSSModel.m Android SDK OSSUtils.java 当您自己实现签名,访问OSS报 SignatureDoesNotMatch 错误时,请使用可视化签名工具确认签名并排除错误。 常见问题 Content-MD5的计算方法 Content-MD5的计算 以消息内容为"123456789"来说,计算这个字符串的Content-MD5 正确的计算方式: 标准中定义的算法简单点说就是: 1. 先计算MD5加密的二进制数组(128位)。 2. 再对这个二进制进行base64编码(而不是对32位字符串编码)。 以Python为例子: 正确计算的代码为: >>> import base64,hashlib >>> hash = hashlib.md5() >>> hash.update("0123456789") >>> base64.b64encode(hash.digest()) 'eB5eJF1ptWaXm4bijSPyxw==' 需要注意 正确的是:hash.digest(),计算出进制数组(128位) >>> hash.digest() 'x\x1e^$]i\xb5f\x97\x9b\x86\xe2\x8d#\xf2\xc7' 常见错误是直接对计算出的32位字符串编码进行base64编码。 例如,错误的是:hash.hexdigest(),计算得到可见的32位字符串编码 >>> hash.hexdigest() '781e5e245d69b566979b86e28d23f2c7' 错误的MD5值进行base64编码后的结果: >>> base64.b64encode(hash.hexdigest()) 'NzgxZTVlMjQ1ZDY5YjU2Njk3OWI4NmUyOGQyM2YyYzc='

2019-12-01 23:13:45 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 用户可以在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错误。 构建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中。此时的CanonicalizedResource如:/BucketName/ObjectName?acl&response-content-type=ContentType&uploadId=UploadId。 说明 OSS目前支持的子资源(sub-resource)包括:acl,uploads,location,cors,logging,website,referer,lifecycle,delete,append,tagging,objectMeta,uploadId,partNumber,security-token,position,img,style,styleName,replication,replicationProgress,replicationLocation,cname,bucketInfo,comp,qos,live,status,vod,startTime,endTime,symlink,x-oss-process,response-content-type,response-content-language,response-expires,response-cache-control,response-content-disposition,response-content-encoding等 子资源(sub-resource)有三种类型: 资源标识,如子资源中的acl,append,uploadId,symlink等,详见关于Bucket的操作和关于Object的操作。 指定返回Header字段,如 response-***,详见GetObject的Request Parameters。 文件(Object)处理方式,如 x-oss-process,用于文件的处理方式,如图片处理。 计算签名头规则 签名的字符串必须为 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就设置为空。 签名示例 假如AccessKeyId是”44CF9590006BF252F707”,AccessKeySecret是”OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV” 请求 签名字符串计算公式 签名字符串 PUT /nelson HTTP/1.0 Content-MD5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra Signature = base64(hmac-sha1(AccessKeySecret,VERB + “\n” + Content-MD5 + “\n”+ Content-Type + “\n” + Date + “\n” + CanonicalizedOSSHeaders+ CanonicalizedResource)) “PUT\n eB5eJF1ptWaXm4bijSPyxw==\n text/html\n Thu, 17 Nov 2005 18:49:58 GMT\n x-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nels 可用以下方法计算签名(Signature): python示例代码: import base64 import hmac import sha h = hmac.new("OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV", "PUT\nODBGOERFMDMzQTczRUY3NUE3NzA5QzdFNUYzMDQxNEM=\ntext/html\nThu, 17 Nov 2005 18:49:58 GMT\nx-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nelson", sha) Signature = base64.b64encode(h.digest()) print("Signature: %s" % Signature) 签名(Signature)计算结果应该为 26NBxoKdsyly4EDv6inkoDft/yA=,因为Authorization = “OSS “ + AccessKeyId + “:” + Signature所以最后Authorization为 “OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA=”然后加上Authorization头来组成最后需要发送的消息: PUT /nelson HTTP/1.0 Authorization:OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA= Content-Md5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra 细节分析 如果传入的AccessKeyId不存在或inactive,返回403 Forbidden。错误码:InvalidAccessKeyId。 若用户请求头中Authorization值的格式不对,返回400 Bad Request。错误码:InvalidArgument。 OSS所有的请求都必须使用HTTP 1.1协议规定的GMT时间格式。其中,日期的格式为:date1 = 2DIGIT SP month SP 4DIGIT; day month year (e.g., 02 Jun 1982)上述日期格式中,“天”所占位数都是“2 DIGIT”。因此,“Jun 2”、“2 Jun 1982”和“2-Jun-82”都是非法日期格式。 如果签名验证的时候,头中没有传入Date或者格式不正确,返回403 Forbidden错误。错误码:AccessDenied。 传入请求的时间必须在OSS服务器当前时间之后的15分钟以内,否则返回403 Forbidden。错误码:RequestTimeTooSkewed。 如果AccessKeyId是active的,但OSS判断用户的请求发生签名错误,则返回403 Forbidden,并在返回给用户的response中告诉用户正确的用于验证加密的签名字符串。用户可以根据OSS的response来检查自己的签名字符串是否正确。返回示例:<?xml version="1.0" ?> <Error> <Code> SignatureDoesNotMatch </Code> <Message> The request signature we calculated does not match the signature you provided. Check your key and signing method. </Message> <StringToSignBytes> 47 45 54 0a 0a 0a 57 65 64 2c 20 31 31 20 4d 61 79 20 32 30 31 31 20 30 37 3a 35 39 3a 32 35 20 47 4d 54 0a 2f 75 73 72 65 61 6c 74 65 73 74 3f 61 63 6c </StringToSignBytes> <RequestId> 1E446260FF9B10C2 </RequestId> <HostId> oss-cn-hangzhou.aliyuncs.com </HostId> <SignatureProvided> y5H7yzPsA/tP4+0tH1HHvPEwUv8= </SignatureProvided> <StringToSign> GET Wed, 11 May 2011 07:59:25 GMT /oss-example?acl </StringToSign> <OSSAccessKeyId> AKIAIVAKMSMOY7VOMRWQ </OSSAccessKeyId> </Error> 说明 OSS SDK已经实现签名,用户使用OSS SDK不需要关注签名问题。如果您想了解具体语言的签名实现,请参考OSS SDK的代码。OSS SDK签名实现的文件如下表: SDK 签名实现 Java SDK OSSRequestSigner.java Python SDK auth.py .Net SDK OssRequestSigner.cs PHP SDK OssClient.php C SDK oss_auth.c JavaScript SDK client.js Go SDK auth.go Ruby SDK util.rb iOS SDK OSSModel.m Android SDK OSSUtils.java 当您自己实现签名,访问OSS报 SignatureDoesNotMatch 错误时,请使用可视化签名工具确认签名并排除错误。 常见问题 Content-MD5的计算方法 Content-MD5的计算 以消息内容为"123456789"来说,计算这个字符串的Content-MD5 正确的计算方式: 标准中定义的算法简单点说就是: 1. 先计算MD5加密的二进制数组(128位)。 2. 再对这个二进制进行base64编码(而不是对32位字符串编码)。 以Python为例子: 正确计算的代码为: >>> import base64,hashlib >>> hash = hashlib.md5() >>> hash.update("0123456789") >>> base64.b64encode(hash.digest()) 'eB5eJF1ptWaXm4bijSPyxw==' 需要注意 正确的是:hash.digest(),计算出进制数组(128位) >>> hash.digest() 'x\x1e^$]i\xb5f\x97\x9b\x86\xe2\x8d#\xf2\xc7' 常见错误是直接对计算出的32位字符串编码进行base64编码。 例如,错误的是:hash.hexdigest(),计算得到可见的32位字符串编码 >>> hash.hexdigest() '781e5e245d69b566979b86e28d23f2c7' 错误的MD5值进行base64编码后的结果: >>> base64.b64encode(hash.hexdigest()) 'NzgxZTVlMjQ1ZDY5YjU2Njk3OWI4NmUyOGQyM2YyYzc='

2019-12-01 23:13:45 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 用户可以在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错误。 构建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中。此时的CanonicalizedResource如:/BucketName/ObjectName?acl&response-content-type=ContentType&uploadId=UploadId。 说明 OSS目前支持的子资源(sub-resource)包括:acl,uploads,location,cors,logging,website,referer,lifecycle,delete,append,tagging,objectMeta,uploadId,partNumber,security-token,position,img,style,styleName,replication,replicationProgress,replicationLocation,cname,bucketInfo,comp,qos,live,status,vod,startTime,endTime,symlink,x-oss-process,response-content-type,response-content-language,response-expires,response-cache-control,response-content-disposition,response-content-encoding等 子资源(sub-resource)有三种类型: 资源标识,如子资源中的acl,append,uploadId,symlink等,详见关于Bucket的操作和关于Object的操作。 指定返回Header字段,如 response-***,详见GetObject的Request Parameters。 文件(Object)处理方式,如 x-oss-process,用于文件的处理方式,如图片处理。 计算签名头规则 签名的字符串必须为 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就设置为空。 签名示例 假如AccessKeyId是”44CF9590006BF252F707”,AccessKeySecret是”OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV” 请求 签名字符串计算公式 签名字符串 PUT /nelson HTTP/1.0 Content-MD5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra Signature = base64(hmac-sha1(AccessKeySecret,VERB + “\n” + Content-MD5 + “\n”+ Content-Type + “\n” + Date + “\n” + CanonicalizedOSSHeaders+ CanonicalizedResource)) “PUT\n eB5eJF1ptWaXm4bijSPyxw==\n text/html\n Thu, 17 Nov 2005 18:49:58 GMT\n x-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nels 可用以下方法计算签名(Signature): python示例代码: import base64 import hmac import sha h = hmac.new("OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV", "PUT\nODBGOERFMDMzQTczRUY3NUE3NzA5QzdFNUYzMDQxNEM=\ntext/html\nThu, 17 Nov 2005 18:49:58 GMT\nx-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nelson", sha) Signature = base64.b64encode(h.digest()) print("Signature: %s" % Signature) 签名(Signature)计算结果应该为 26NBxoKdsyly4EDv6inkoDft/yA=,因为Authorization = “OSS “ + AccessKeyId + “:” + Signature所以最后Authorization为 “OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA=”然后加上Authorization头来组成最后需要发送的消息: PUT /nelson HTTP/1.0 Authorization:OSS 44CF9590006BF252F707:26NBxoKdsyly4EDv6inkoDft/yA= Content-Md5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra 细节分析 如果传入的AccessKeyId不存在或inactive,返回403 Forbidden。错误码:InvalidAccessKeyId。 若用户请求头中Authorization值的格式不对,返回400 Bad Request。错误码:InvalidArgument。 OSS所有的请求都必须使用HTTP 1.1协议规定的GMT时间格式。其中,日期的格式为:date1 = 2DIGIT SP month SP 4DIGIT; day month year (e.g., 02 Jun 1982)上述日期格式中,“天”所占位数都是“2 DIGIT”。因此,“Jun 2”、“2 Jun 1982”和“2-Jun-82”都是非法日期格式。 如果签名验证的时候,头中没有传入Date或者格式不正确,返回403 Forbidden错误。错误码:AccessDenied。 传入请求的时间必须在OSS服务器当前时间之后的15分钟以内,否则返回403 Forbidden。错误码:RequestTimeTooSkewed。 如果AccessKeyId是active的,但OSS判断用户的请求发生签名错误,则返回403 Forbidden,并在返回给用户的response中告诉用户正确的用于验证加密的签名字符串。用户可以根据OSS的response来检查自己的签名字符串是否正确。返回示例:<?xml version="1.0" ?> <Error> <Code> SignatureDoesNotMatch </Code> <Message> The request signature we calculated does not match the signature you provided. Check your key and signing method. </Message> <StringToSignBytes> 47 45 54 0a 0a 0a 57 65 64 2c 20 31 31 20 4d 61 79 20 32 30 31 31 20 30 37 3a 35 39 3a 32 35 20 47 4d 54 0a 2f 75 73 72 65 61 6c 74 65 73 74 3f 61 63 6c </StringToSignBytes> <RequestId> 1E446260FF9B10C2 </RequestId> <HostId> oss-cn-hangzhou.aliyuncs.com </HostId> <SignatureProvided> y5H7yzPsA/tP4+0tH1HHvPEwUv8= </SignatureProvided> <StringToSign> GET Wed, 11 May 2011 07:59:25 GMT /oss-example?acl </StringToSign> <OSSAccessKeyId> AKIAIVAKMSMOY7VOMRWQ </OSSAccessKeyId> </Error> 说明 OSS SDK已经实现签名,用户使用OSS SDK不需要关注签名问题。如果您想了解具体语言的签名实现,请参考OSS SDK的代码。OSS SDK签名实现的文件如下表: SDK 签名实现 Java SDK OSSRequestSigner.java Python SDK auth.py .Net SDK OssRequestSigner.cs PHP SDK OssClient.php C SDK oss_auth.c JavaScript SDK client.js Go SDK auth.go Ruby SDK util.rb iOS SDK OSSModel.m Android SDK OSSUtils.java 当您自己实现签名,访问OSS报 SignatureDoesNotMatch 错误时,请使用可视化签名工具确认签名并排除错误。 常见问题 Content-MD5的计算方法 Content-MD5的计算 以消息内容为"123456789"来说,计算这个字符串的Content-MD5 正确的计算方式: 标准中定义的算法简单点说就是: 1. 先计算MD5加密的二进制数组(128位)。 2. 再对这个二进制进行base64编码(而不是对32位字符串编码)。 以Python为例子: 正确计算的代码为: >>> import base64,hashlib >>> hash = hashlib.md5() >>> hash.update("0123456789") >>> base64.b64encode(hash.digest()) 'eB5eJF1ptWaXm4bijSPyxw==' 需要注意 正确的是:hash.digest(),计算出进制数组(128位) >>> hash.digest() 'x\x1e^$]i\xb5f\x97\x9b\x86\xe2\x8d#\xf2\xc7' 常见错误是直接对计算出的32位字符串编码进行base64编码。 例如,错误的是:hash.hexdigest(),计算得到可见的32位字符串编码 >>> hash.hexdigest() '781e5e245d69b566979b86e28d23f2c7' 错误的MD5值进行base64编码后的结果: >>> base64.b64encode(hash.hexdigest()) 'NzgxZTVlMjQ1ZDY5YjU2Njk3OWI4NmUyOGQyM2YyYzc='

2019-12-01 23:13:44 0 浏览量 回答数 0

问题

OpenSearch的数据源及插件是什么?

轩墨 2019-12-01 20:55:51 1089 浏览量 回答数 0

问题

手把手学IOT服务端API编程[5、批量设备注册][step by step ALI-IOT-SERVER-API]

洵云 2019-12-01 22:01:23 1384 浏览量 回答数 2

回答

各语言公钥证书方式sdk内签名生成sign值及各语言回调数据验签示例代码。 开放平台SDK(如接口调用是使用execute和certificateExecute方法进行提交的)是封装了同步返回响应参数的验签方法,只需在创建DefaultAlipayClient对象进行初始化,设置请求网关(gateway),应用id(app_id),应用私钥(private_key),编码格式(charset),支付宝公钥(alipay_public_key),签名类型(sign_type)即可,同步返回响应参数报文时会自动进行验签,无需自己再单独对同步响应数据作验签处理。 注:本文示例代码仅供测试参考 java语言: 签名方法: //请求的待签名字符串(需要在待签名字符串中加alipay_root_cert_sn和app_cert_sn) String content = "app_id=201***222&biz_content={}&******...."; //私钥 String privateKey=""; //编码格式 String charset="utf-8"; //签名方式 String sign_type="RSA2"; //签名方法 String sign=AlipaySignature.rsaSign(content, privateKey, charset,sign_type); System.out.println("sign:"+ sign); 验签方法: 异步同步通知数据验签: //回调的待验签字符串 String resultInfo = "buyer_id=2042&total_amount=0.01&body=..."; //编码格式 String charset="GBK"; //支付宝公钥 String alipayPublicCertPath="支付宝公钥证书绝对路径"; //签名方式 String sign_type="RSA2"; //对待签名字符串数据通过&进行拆分 String [] temp = resultInfo.split("&"); LinkedHashMap<String, String> map = new LinkedHashMap<String, String>(); //把拆分数据放在map集合内 for (int i = 0; i < temp.length; i++) { String[] arr = temp[i].split("=", 2); //通过"="号分割成2个数据 String[] tempAagin = new String[arr.length]; //再开辟一个数组用来接收分割后的数据 for (int j = 0; j < arr.length; j++) { tempAagin[j] = arr[j]; } map.put(tempAagin[0], tempAagin[1]); } System.out.println(map); //验签方法 boolean signVerified= AlipaySignature.rsaCertCheckV1(map, alipayPublicCertPath, charset,sign_type); if(signVerified){ // TODO 验签成功后 System.out.println("success"); }else{ System.out.println("fail"); } 生活号响应返回的数据验签: //回调的待验签字符串 String resultInfo = "biz_content= ...."; //编码格式 String charset="GBK"; //支付宝公钥 String alipayPublicCertPath="支付宝公钥证书绝对路径"; //签名方式 String sign_type="RSA2"; //对待签名字符串数据通过&进行拆分 String [] temp = resultInfo.split("&"); LinkedHashMap<String, String> map = new LinkedHashMap<String, String>(); //把拆分数据放在map集合内 for (int i = 0; i < temp.length; i++) { String[] arr = temp[i].split("=", 2); //通过"="号分割成2个数据 String[] tempAagin = new String[arr.length]; //再开辟一个数组用来接收分割后的数据 for (int j = 0; j < arr.length; j++) { tempAagin[j] = arr[j]; } map.put(tempAagin[0], tempAagin[1]); } System.out.println(map); //验签方法 boolean signVerified= AlipaySignature.rsaCertCheckV2(map, alipayPublicCertPath, charset,sign_type); if(signVerified){ // TODO 验签成功后 System.out.println("success"); }else{ System.out.println("fail"); } 同步响应数据验签: //响应的待验签字符串 String content = "{"code":"10000","msg":"Success","out_trade_no":"20190862203200101010018","qr_code":"https:\/\/qr.alipay.com\/89545488784"}"; //响应数据返回的sign值 String sign=""; //编码格式 String charset="utf-8"; //支付宝公钥 String alipayPublicCertPath="支付宝公钥证书绝对路径"; //签名方式 String sign_type="RSA2"; //验签方法 boolean signVerified= AlipaySignature.rsaCertCheck(content, sign, alipayPublicCertPath, charset, sign_type); if(signVerified){ // TODO 验签成功后 System.out.println("success"); }else{ System.out.println("fail"); } php语言: 签名方法: $aop = new AopCertClient(); //私钥 $privatekey=""; //签名方式 $signType="RSA2"; //待签名字符串(需要在待签名字符串中加alipay_root_cert_sn和app_cert_sn) $data="app_id=201***222&biz_content={}&******...."; //sdk内封装的签名方法 $sign=$aop->alonersaSign($data,$privatekey,$signType,false); echo "sign:".$sign; 验签方法: 异步同步通知数据验签: $aop = new AopCertClient(); //证书路径 $alipayCertPath = "支付宝公钥证书绝对路径"; //支付宝公钥赋值 $aop->alipayrsaPublicKey = $aop->getPublicKey($alipayCertPath); //待签名字符串 $_POST="buyer_id=2042&total_amount=0.01&body=..."; //签名方式 $sign_type="RSA2"; //把字符串通过&符号拆分成数组 $data = explode("&", $_POST); $params = array(); //遍历数组 foreach ($data as $param) { $item = explode('=',$param,"2"); $params[$item[0]] = $item[1]; } //输出拆分后的数据数据 print_r($params); //验签代码 $flag = $aop->rsaCheckV1($params, null, $sign_type); if ($flag) { echo "success"; } else { echo "fail"; } 生活号响应返回的数据验签: $aop = new AopCertClient(); //证书路径 $alipayCertPath = "支付宝公钥证书绝对路径"; //支付宝公钥赋值 $aop->alipayrsaPublicKey = $aop->getPublicKey($alipayCertPath); //待签名字符串 $_POST="biz_content= &sign=W2bSxqt4W9Tspjx+Cem5AfvJcphh7mAbKCWrwawOFDSAnqUJqWjvtt6qwqt63RZ/lDip0iyl9UAY0U2AqQBFyv1+lCI3bw/XqXIHY819EsZMxB13kf6926t5a/hB9vC1pEAcBenw5PanXQtRSCnpC29eUUyqce3I9cZyjaa/LCRaQjv5s6FIAJ4oKEN3ns/YXd1GSk2urR4x2SVA87D/+DZ5briesccVAN82A1DDuW40Rx1eWgSaP8gkN6vEEW2pAjBp6yNcCsZ6o799LIIOBgBZuMaQdJiFq6lhqSdZ/OdPRGTN5kWpJsMUhkSnyBbFYiWeDVuaQv5hd0GPLQZmsw==&sign_type=RSA2&service=alipay.service.check&charset=GBK"; //签名方式 $sign_type="RSA2"; //把字符串通过&符号拆分成数组 $data = explode('&', $_POST); $params = array(); //遍历数组 foreach ($data as $param) { $item = explode('=', $param,'2'); $params[$item[0]] = $item[1]; } //验签代码 $flag = $aop->rsaCheckV2($params, null, $sign_type); if ($flag) { echo "success"; } else { echo "fail"; } 同步响应数据验签: $aop = new AopCertClient(); //证书路径 $alipayCertPath = "支付宝公钥证书绝对路径"; //支付宝公钥赋值 $aop->alipayrsaPublicKey = $aop->getPublicKey($alipayCertPath); //待签名字符串 $_POST="{"code":"10000","msg":"Success","app_id":"2015","auth_app_id":"20141*****75","charset":"utf-8","timestamp":"2019-04-01 14:33:01","out_trade_no":"0401022927-9449","total_amount":"0.01","trade_no":"201473539","seller_id":"208***5"}"; //sign值 $sign=""; //签名方式 $sign_type="RSA2"; //验签代码 $flag = $aop->verify($_POST, $sign,null,$sign_type); if ($flag) { echo "success"; } else { echo "fail"; } .net语言: 签名方法: //请求的待签名字符串(需要在待签名字符串中加alipay_root_cert_sn和app_cert_sn) string content = "app_id=20141***22&biz_content={"out_trade_no":"2019040***6451724","total_amount":"0.01"}&charset=UTF-8......"; //应用私钥:PKCS1格式 string privateKey = ""; //签名方法 string sign = AlipaySignature.RSASign(content, privateKey, "UTF-8", "RSA2", false); Response.Write("sign:" + sign); 验签方法: 异步同步通知数据验签: //异步通知参数 string str = "buyer_id=20880*42&total_amount=0.01&body=......."; string charset = "utf-8"; string sign_type = "RSA2"; var dics = new Dictionary<string, string>(); var rearray = str.Split('&'); foreach (var a in rearray) { var array = a.IndexOf('='); dics.Add(a.Substring(0, array), a.Substring(array + 1)); Response.Write(a + "<br/>"); } //支付宝公钥 string alipayPublicCertPath = "支付宝公钥证书绝对路径"; //验签方法 bool flag = AlipaySignature.RSACertCheckV1(dics, alipayPublicCertPath, charset, sign_type); Response.Write(flag); 生活号响应返回的数据验签: //异步通知参数 string str = "biz_content= *****"; string charset = "utf-8"; string sign_type = "RSA2"; var dics = new Dictionary<string, string>(); var rearray = str.Split('&'); foreach (var a in rearray) { var array = a.IndexOf('='); dics.Add(a.Substring(0, array), a.Substring(array + 1)); Response.Write(a + "<br/>"); } //支付宝公钥 string alipayPublicCertPath = "支付宝公钥证书绝对路径"; //验签方法 bool flag = AlipaySignature.RSACertCheckV2(dics, alipayPublicCertPath, charset, sign_type); Response.Write(flag); 同步响应数据验签: //同步响应返回的{}内的数据包含{} string str = "{"code":"10000","msg":"Success","app_id":"20115775","auth_app_id":"20*0015775","charset":"utf-8","timestamp":"2019-04-01 14:33:01","out_trade_no":"0401022927-9449","total_amount":"0.01","trade_no":"2019040122001456751039","seller_id":"20886**35"}"; string charset = "utf-8"; string sign_type = "RSA2"; string sign = ""; //解析支付宝公钥的值 string alipayPublicCertPath = "支付宝公钥绝对路径"; //X509Certificate定义需引用using Org.BouncyCastle.X509 X509Certificate alipayPublicKeyCert = AntCertificationUtil.ParseCert(File.ReadAllText(alipayPublicCertPath)); string alipayPublicKey = AntCertificationUtil.ExtractPemPublicKeyFromCert(alipayPublicKeyCert); //验签方法 bool flag = AlipaySignature.RSACheckContent(str, sign, alipayPublicKey, charset, sign_type, false); //输出验签结果 Response.Write(flag);

保持可爱mmm 2020-05-05 16:50:43 0 浏览量 回答数 0

回答

OpenSearch服务会对每个访问的请求进行身份验证,通过使用Access Key ID和Access Key Secret进行对称加密的方法来验证请求的发送者身份。 Access Key ID和Access Key Secret由阿里云官方颁发给访问者(可以通过阿里云官方网站申请和管理),其中Access Key ID用于标识访问者的身份。 Access Key Secret是用于加密签名字符串和服务器端验证签名字符串的密钥,必须严格保密,只有阿里云和用户知道。 支持应用类型 高级版 标准版 通信协议 只支持 HTTP 协议 请求对应方式 搜索数据必须使用:GET 推送数据必须使用:POST Authorization 字段计算方法 需在 HTTP 请求 Header 头信息中,添加 Authorization(授权)来包含签名(Signature)信息,表明该请求已被授权。请求Header 中也需要包含文档下面“签名示例”部分中“请求Header”中提到的这些相关的请求Header。 请求 Header 中包含的参数都必须要参与签名(例如 Content-Md5,Content-Type,Date,Http专有 Header 等等)。 "Authorization: OPENSEARCH " + AccessKeyId + ":" + Signature Signature = base64(hmac-sha1(AccessKeySecret, VERB + "\n" + Content-Md5 + "\n" + Content-Type + "\n" + Date + "\n" + CanonicalizedOpenSearchHeaders + CanonicalizedResource)) 按照RFC2104的定义,使用上面的用于签名的字符串计算签名HMAC值 签名的方法用 RFC 2104 中定义的 HMAC-SHA1 方法 签名的字符串必须为UTF-8格式 含有中文字符的签名字符串必须先进行UTF-8编码,再与AccessKeySecret计算最终签名 签名参数先后顺序,必须和上面保持一致 参数 描述 AccessKeyId 不能为空,请求Header 中的 Authorization 需要用到该 AccessKeyId 值,表示访问指定应用的用户 AccessKeySecret 不能为空,签名所需的秘钥 VERB 不能为空,表示请求操作方法。HTTP 请求 Method,主要有 PUT、GET、POST、HEAD、DELETE 等,不同接口Method也不同 \n 换行符 Content-MD5 请求body有内容时,不能为空。该参数值为,请求body 的MD5值。该请求头用于消息合法性的检查(消息内容是否与发送时一致),例如 4991ef0788236a8f280fed0db928e74e ,对于不发送 body 的请求,例如查询请求,此值请留空。详情参看 RFC2616 Content-MD5 Content-Type application/json Date 不能为空,表示此次操作时间,且必须为 秒级 的 ISO 格式,如2019-02-25T10:09:57Z,时间为UTC时间;如果此时间和 OpenSearch 服务器的时间差正负 15 分钟以上,服务器将拒绝该服务,并返回 HTTP 403 错误 CanonicalizedOpenSearchHeaders 不能为空,用于区分每次请求,以 X-Opensearch- 为前缀的Http专有 Header组合,例如 X-Opensearch-Nonce,在签名过程中这些Http专有 Header名必须全部小写,例如 x-opensearch-nonce,若这些Http专有Header是作为请求Header参数,则需按照原格式名显示 若请求 Header 中不包含这些Http专有 Header,该参数不参与签名计算,在签名方法中直接去掉该参数。 CanonicalizedResource 不能为空,表示用户此次请求路径,例如 /v3/openapi/apps/app_schema_demo/search?fetch_fields=name&query=query%3Dname%3A%27%E6%96%87%E6%A1%A3%27&&sort%3Did&&config%3Dformat%3Afulljson 查询请求 请求签名参数 必须 请求 Header 参数 必须 AccessKeySecret 是 Date 是 VERB 是 X-Opensearch-Nonce 是 Date 是 Authorization 是 x-opensearch-nonce 是 canonicalized_resource 是 Header 中的参数值必须要与对应签名方法中的参数值一致 建议将 Content-Md5,Content-Type,Date,CanonicalizedOpenSearchHeaders,Authorization 这些参数都添加到请求Header中,只包含必须参数可能会出现报错,需避免 请求 Header 中包含的参数都必须要参与签名 推送请求 请求签名参数 必须 请求 Header 参数 必须 AccessKeySecret 是 Content-MD5 是 VERB 是 Date 是 Content-MD5 是 Authorization 是 Date 是 canonicalized_resource 是 Header 中的参数值必须要与对应签名方法中的参数值一致 理论上 Content-Md5,Content-Type,Date,CanonicalizedOpenSearchHeaders,Authorization 这些参数都需要添加到请求Header中,只包含必须参数可能会出现报错,需避免 请求 Header 中包含的参数都必须要参与签名 构建CanonicalizedOpenSearchHeaders的方法 所有以 X-Opensearch- 为前缀的 Http专有 Header 被称为 CanonicalizedOpenSearchHeaders,其他非 Http专有 Header 将不被纳入验证 将所有以 X-Opensearch- 为前缀的Http专有 Header 对应的内容补齐,例如X-Opensearch-Nonce : 1551089397451704(该Nonce参数值,可由10位时间戳+6位随机值(100000~999999)组合而成,例如1551089397451704),再去除所有值为空的Http专有 Header 将这些有对应内容值的Http专有 Header 按照名称的字典序进行升序排序 再将这些排序后的专有 Header名,全部转换成小写字母,例如将 X-Opensearch-Nonce : 1551089397451704 转换成 x-opensearch-nonce : 1551089397451704 删除请求头和内容之间分隔符两端出现的任何空格。例如该 x-opensearch-nonce : 1551089397451704 参数,删除两端空格后为:x-opensearch-nonce:1551089397451704 最后将每个请求头及对应内容作为一个单位项,再将每一项之间用 \n 连接拼成最后的 CanonicalizedOpenSearchHeaders,注意最后一个也要有 \n 注意: 若查询请求Header中不包含此处Http专有 Header,即该参数中一个Http专有 Header都没有,则无需 \n,只需在签名方法中去掉该CanonicalizedOpenSearchHeaders签名参数即可,该参数不参与签名计算。 将Http专有 Header添加到Header中时,不能是转换后的小写形式,需按原格式显示 构建CanonicalizedResource的方法 签名的字符串必须为UTF-8格式,且含有中文字符的签名字符串必须先进行 UTF-8 编码,再与 AccessKeySecret 计算最终签名 查询 CanonicalizedResource = path + ? + query 推送 CanonicalizedResource = path 构建 path 部分 对 path 进行urlencode后,再替换 %2F 为 /,下面的app_schema_demo需替换为自己应用名,常见 path 如下所示 search查询path /v3/openapi/apps/app_schema_demo/search suggest查询path /v3/openapi/apps/app_schema_demo/suggest/suggest/search 最终查询指定应用信息查询请求串,下面“appid”需替换为待查询的应用ID,需包含Authorization授权签名参数(无需指定查询参数) /v3/openapi/apps/appid 推送数据path(tab 是要推送到应用中的某个具体表名,也需替换为自己应用表名) /v3/openapi/apps/app_schema_demo/tab/actions/bulk 构建 query 部分 query 部分由查询参数构成,参数为键值对形式 为需要指定的查询参数设置对应的参数值,并去掉value为空的参数(value为空的参数不计算签名) 再对每一个参数按照先比较参数名后比较参数值的顺序,按照字典升序 再对每一部分的参数名和参数值进行 urlencode,再将参数名和对应参数值之间通过=拼接 再将各个查询参数之间用 & 分割拼接并存储到 query 字符串中 再将该 query 字符串中的+字符,替换成%20。注意如果有&&字符,也需替换成&&。 最后按照 path + ? + query 方式拼接至CanonicalizedResource字符串中,即完成查询操作CanonicalizedResource参数构建,示例如下: /v3/openapi/apps/app_schema_demo/search?fetch_fields=name&query=query%3Dname%3A%27%E6%96%87%E6%A1%A3%27&&sort%3Did&&config%3Dformat%3Afulljson 以上请求串中主要包含的参数及参数值描述如下: fetch_fields=name 以上请求串中主要包含的query参数中各子句及参数值描述如下(第一个是query参数,第二个是query子句及其它相关子句): query=query=name:'文档'&&sort=id&&config=format:fulljson 注意: query参数中各个查询子句之间必须要用 && 进行拼接 若为推送操作,则只需将 path 部分拼接至 CanonicalizedResource 字符串中即可 构建 Authorization 字段 构建方法参考开头部分描述,需添加到请求 Header 中。假如AccessKeyId 为LTAItQcybixtR9A0,Signature为 1P7tfEh+CU5kFYRXzZ14kkJUAMc=,则python3示例代码大致如下: headers['Authorization'] = 'OPENSEARCH ' + 'LTAItQcybixtR9A0' + ':' + '1P7tfEh+CU5kFYRXzZ14kkJUAMc=' 签名示例 假如参数值如下 Authorization值为OPENSEARCH LTAItQcybixtR9A0:1P7tfEh+CU5kFYRXzZ14kkJUAMc= AccessKeySecret值为 R0OGKsMj0etgyA9nZM5ykhMqHXBfKG 请求方式为GET Content-MD5值为空,此处作为查询请求 Content-Type值为application/json Date值为2019-02-25T10:09:57Z CanonicalizedOpenSearchHeaders值为x-opensearch-nonce:1551089397451704 CanonicalizedResource值为/v3/openapi/apps/app_schema_demo/search?fetch_fields=name&query=query%3Dname%3A%27%E6%96%87%E6%A1%A3%27&&sort%3Did&&config%3Dformat%3Afulljson 请求Header 签名字符串计算公式 签名字符串 ‘Content-MD5’: ‘’, ‘Content-Type’: ‘application/json’, ‘Authorization’: ‘OPENSEARCH LTAItQcybixtR9A0:1P7tfEh+CU5kFYRXzZ14kkJUAMc=’, ‘X-Opensearch-Nonce’: ‘1551089397451704’, ‘Date’: ‘2019-02-25T10:09:57Z’ Signature = base64(hmac-sha1( AccessKeySecret, VERB + “\n” + Content-Md5 + “\n” + Content-Type + “\n” + Date + “\n” + CanonicalizedOpenSearchHeaders + CanonicalizedResource)) 1P7tfEh+CU5kFYRXzZ14kkJUAMc= , GET\n \n application/json\n 2019-02-25T10:09:57Z\n x-opensearch-nonce:1551089397451704\n /v3/openapi/apps/app_schema_demo/search?fetch_fields=name&query=query%3Dname%3A%27%E6%96%87%E6%A1%A3%27&&sort%3Did&&config%3Dformat%3Afulljson 注意: 请求Header中参数值需与签名方法中对应参数值保持一致 可用以下方法计算签名(Signature) 以 hash_hmac 和 base64_encode 编码生成加密值作为Signature python3 示例代码: import hmac import base64 signature_string = '\n'.join(['GET', '', 'application/json', '2019-02-25T10:09:57Z', 'x-opensearch-nonce:1551089397451704', '/v3/openapi/apps/app_schema_demo/search?fetch_fields=name&query=query%3Dname%3A%27%E6%96%87%E6%A1%A3%27&&sort%3Did&&config%3Dformat%3Afulljson']) signature_hmac = hmac.new('R0OGKsMj0etgyA9nZM5ykhMqHXBfKG'.encode('utf-8'), signature_string.encode('utf-8'), 'sha1') signature = base64.b64encode(signature_hmac.digest()) 假如AccessKeySecret值为 R0OGKsMj0etgyA9nZM5ykhMqHXBfKG 那么通过上面的签名方法构造出来的签名值为 1P7tfEh+CU5kFYRXzZ14kkJUAMc= 构建请求串 请求串 = host + CanonicalizedResource 需在 HTTP 请求 Header 头信息中增加 Authorization(授权)来包含签名(Signature)信息,表明该请求已被授权,同时Header中也需要包含上面提到的这些相关的请求Header。(host为应用访问API地址) 最终search查询请求串 http://host/v3/openapi/apps/app_schema_demo/search?fetch_fields=name&query=query%3Dname%3A%27%E6%96%87%E6%A1%A3%27&&sort%3Did&&config%3Dformat%3Afulljson 最终suggest查询请求串 http://host/v3/openapi/apps/app_schema_demo/suggest/suggest/search?query=%E6%A0%87%E9%A2%98&hits=10 最终查询指定应用信息查询请求串,下面最后一部分为“appid”值,假设为120001234该值,替换后如下所示,该查询请求也需包含Authorization授权签名参数(无需指定查询参数) http://host/v3/openapi/apps/120001234 最终推送数据请求串,此处推送数据需放在body体中 http://host/v3/openapi/apps/app_schema_demo/tab/actions/bulk v3API签名Demo 目前已对外公开 v3版官方Java SDK 和 PHP SDK,且PHP SDK已包含v3API签名过程实现源码,直接调用这些方法即可使用,也可参考 PHP SDK 签名实现过程源码,或参考本文档v3API签名过程来实现其它语言SDK。 因目前OpenSearch官方,没有正式对外提供官方的 python版 和 C#版 SDK,为方便用户参考实现该文档描述签名过程,此处提供 python及C#版查询和推送签名Demo,以供用户参考实现本文档签名操作。 注意: 此处提供 Demo 仅供参考,后续用户参考此 Demo 实现的 SDK 由用户自己维护。

保持可爱mmm 2020-03-26 21:56:23 0 浏览量 回答数 0

回答

OpenSearch服务会对每个访问的请求进行身份验证,通过使用Access Key ID和Access Key Secret进行对称加密的方法来验证请求的发送者身份。 Access Key ID和Access Key Secret由阿里云官方颁发给访问者(可以通过阿里云官方网站申请和管理),其中Access Key ID用于标识访问者的身份。 Access Key Secret是用于加密签名字符串和服务器端验证签名字符串的密钥,必须严格保密,只有阿里云和用户知道。 支持应用类型 高级版 标准版 通信协议 只支持 HTTP 协议 请求对应方式 搜索数据必须使用:GET 推送数据必须使用:POST Authorization 字段计算方法 需在 HTTP 请求 Header 头信息中,添加 Authorization(授权)来包含签名(Signature)信息,表明该请求已被授权。请求Header 中也需要包含文档下面“签名示例”部分中“请求Header”中提到的这些相关的请求Header。 请求 Header 中包含的参数都必须要参与签名(例如 Content-Md5,Content-Type,Date,Http专有 Header 等等)。 "Authorization: OPENSEARCH " + AccessKeyId + ":" + Signature Signature = base64(hmac-sha1(AccessKeySecret, VERB + "\n" + Content-Md5 + "\n" + Content-Type + "\n" + Date + "\n" + CanonicalizedOpenSearchHeaders + CanonicalizedResource)) 按照RFC2104的定义,使用上面的用于签名的字符串计算签名HMAC值 签名的方法用 RFC 2104 中定义的 HMAC-SHA1 方法 签名的字符串必须为UTF-8格式 含有中文字符的签名字符串必须先进行UTF-8编码,再与AccessKeySecret计算最终签名 签名参数先后顺序,必须和上面保持一致 参数 描述 AccessKeyId 不能为空,请求Header 中的 Authorization 需要用到该 AccessKeyId 值,表示访问指定应用的用户 AccessKeySecret 不能为空,签名所需的秘钥 VERB 不能为空,表示请求操作方法。HTTP 请求 Method,主要有 PUT、GET、POST、HEAD、DELETE 等,不同接口Method也不同 \n 换行符 Content-MD5 请求body有内容时,不能为空。该参数值为,请求body 的MD5值。该请求头用于消息合法性的检查(消息内容是否与发送时一致),例如 4991ef0788236a8f280fed0db928e74e ,对于不发送 body 的请求,例如查询请求,此值请留空。详情参看 RFC2616 Content-MD5 Content-Type application/json Date 不能为空,表示此次操作时间,且必须为 秒级 的 ISO 格式,如2019-02-25T10:09:57Z,时间为UTC时间;如果此时间和 OpenSearch 服务器的时间差正负 15 分钟以上,服务器将拒绝该服务,并返回 HTTP 403 错误 CanonicalizedOpenSearchHeaders 不能为空,用于区分每次请求,以 X-Opensearch- 为前缀的Http专有 Header组合,例如 X-Opensearch-Nonce,在签名过程中这些Http专有 Header名必须全部小写,例如 x-opensearch-nonce,若这些Http专有Header是作为请求Header参数,则需按照原格式名显示 若请求 Header 中不包含这些Http专有 Header,该参数不参与签名计算,在签名方法中直接去掉该参数。 CanonicalizedResource 不能为空,表示用户此次请求路径,例如 /v3/openapi/apps/app_schema_demo/search?fetch_fields=name&query=query%3Dname%3A%27%E6%96%87%E6%A1%A3%27&&sort%3Did&&config%3Dformat%3Afulljson 查询请求 请求签名参数 必须 请求 Header 参数 必须 AccessKeySecret 是 Date 是 VERB 是 X-Opensearch-Nonce 是 Date 是 Authorization 是 x-opensearch-nonce 是 canonicalized_resource 是 Header 中的参数值必须要与对应签名方法中的参数值一致 建议将 Content-Md5,Content-Type,Date,CanonicalizedOpenSearchHeaders,Authorization 这些参数都添加到请求Header中,只包含必须参数可能会出现报错,需避免 请求 Header 中包含的参数都必须要参与签名 推送请求 请求签名参数 必须 请求 Header 参数 必须 AccessKeySecret 是 Content-MD5 是 VERB 是 Date 是 Content-MD5 是 Authorization 是 Date 是 canonicalized_resource 是 Header 中的参数值必须要与对应签名方法中的参数值一致 理论上 Content-Md5,Content-Type,Date,CanonicalizedOpenSearchHeaders,Authorization 这些参数都需要添加到请求Header中,只包含必须参数可能会出现报错,需避免 请求 Header 中包含的参数都必须要参与签名 构建CanonicalizedOpenSearchHeaders的方法 所有以 X-Opensearch- 为前缀的 Http专有 Header 被称为 CanonicalizedOpenSearchHeaders,其他非 Http专有 Header 将不被纳入验证 将所有以 X-Opensearch- 为前缀的Http专有 Header 对应的内容补齐,例如X-Opensearch-Nonce : 1551089397451704(该Nonce参数值,可由10位时间戳+6位随机值(100000~999999)组合而成,例如1551089397451704),再去除所有值为空的Http专有 Header 将这些有对应内容值的Http专有 Header 按照名称的字典序进行升序排序 再将这些排序后的专有 Header名,全部转换成小写字母,例如将 X-Opensearch-Nonce : 1551089397451704 转换成 x-opensearch-nonce : 1551089397451704 删除请求头和内容之间分隔符两端出现的任何空格。例如该 x-opensearch-nonce : 1551089397451704 参数,删除两端空格后为:x-opensearch-nonce:1551089397451704 最后将每个请求头及对应内容作为一个单位项,再将每一项之间用 \n 连接拼成最后的 CanonicalizedOpenSearchHeaders,注意最后一个也要有 \n 注意: 若查询请求Header中不包含此处Http专有 Header,即该参数中一个Http专有 Header都没有,则无需 \n,只需在签名方法中去掉该CanonicalizedOpenSearchHeaders签名参数即可,该参数不参与签名计算。 将Http专有 Header添加到Header中时,不能是转换后的小写形式,需按原格式显示 构建CanonicalizedResource的方法 签名的字符串必须为UTF-8格式,且含有中文字符的签名字符串必须先进行 UTF-8 编码,再与 AccessKeySecret 计算最终签名 查询 CanonicalizedResource = path + ? + query 推送 CanonicalizedResource = path 构建 path 部分 对 path 进行urlencode后,再替换 %2F 为 /,下面的app_schema_demo需替换为自己应用名,常见 path 如下所示 search查询path /v3/openapi/apps/app_schema_demo/search suggest查询path /v3/openapi/apps/app_schema_demo/suggest/suggest/search 最终查询指定应用信息查询请求串,下面“appid”需替换为待查询的应用ID,需包含Authorization授权签名参数(无需指定查询参数) /v3/openapi/apps/appid 推送数据path(tab 是要推送到应用中的某个具体表名,也需替换为自己应用表名) /v3/openapi/apps/app_schema_demo/tab/actions/bulk 构建 query 部分 query 部分由查询参数构成,参数为键值对形式 为需要指定的查询参数设置对应的参数值,并去掉value为空的参数(value为空的参数不计算签名) 再对每一个参数按照先比较参数名后比较参数值的顺序,按照字典升序 再对每一部分的参数名和参数值进行 urlencode,再将参数名和对应参数值之间通过=拼接 再将各个查询参数之间用 & 分割拼接并存储到 query 字符串中 再将该 query 字符串中的+字符,替换成%20。注意如果有&&字符,也需替换成&&。 最后按照 path + ? + query 方式拼接至CanonicalizedResource字符串中,即完成查询操作CanonicalizedResource参数构建,示例如下: /v3/openapi/apps/app_schema_demo/search?fetch_fields=name&query=query%3Dname%3A%27%E6%96%87%E6%A1%A3%27&&sort%3Did&&config%3Dformat%3Afulljson 以上请求串中主要包含的参数及参数值描述如下: fetch_fields=name 以上请求串中主要包含的query参数中各子句及参数值描述如下(第一个是query参数,第二个是query子句及其它相关子句): query=query=name:'文档'&&sort=id&&config=format:fulljson 注意: query参数中各个查询子句之间必须要用 && 进行拼接 若为推送操作,则只需将 path 部分拼接至 CanonicalizedResource 字符串中即可 构建 Authorization 字段 构建方法参考开头部分描述,需添加到请求 Header 中。假如AccessKeyId 为LTAItQcybixtR9A0,Signature为 1P7tfEh+CU5kFYRXzZ14kkJUAMc=,则python3示例代码大致如下: headers['Authorization'] = 'OPENSEARCH ' + 'LTAItQcybixtR9A0' + ':' + '1P7tfEh+CU5kFYRXzZ14kkJUAMc=' 签名示例 假如参数值如下 Authorization值为OPENSEARCH LTAItQcybixtR9A0:1P7tfEh+CU5kFYRXzZ14kkJUAMc= AccessKeySecret值为 R0OGKsMj0etgyA9nZM5ykhMqHXBfKG 请求方式为GET Content-MD5值为空,此处作为查询请求 Content-Type值为application/json Date值为2019-02-25T10:09:57Z CanonicalizedOpenSearchHeaders值为x-opensearch-nonce:1551089397451704 CanonicalizedResource值为/v3/openapi/apps/app_schema_demo/search?fetch_fields=name&query=query%3Dname%3A%27%E6%96%87%E6%A1%A3%27&&sort%3Did&&config%3Dformat%3Afulljson 请求Header 签名字符串计算公式 签名字符串 ‘Content-MD5’: ‘’, ‘Content-Type’: ‘application/json’, ‘Authorization’: ‘OPENSEARCH LTAItQcybixtR9A0:1P7tfEh+CU5kFYRXzZ14kkJUAMc=’, ‘X-Opensearch-Nonce’: ‘1551089397451704’, ‘Date’: ‘2019-02-25T10:09:57Z’ Signature = base64(hmac-sha1( AccessKeySecret, VERB + “\n” + Content-Md5 + “\n” + Content-Type + “\n” + Date + “\n” + CanonicalizedOpenSearchHeaders + CanonicalizedResource)) 1P7tfEh+CU5kFYRXzZ14kkJUAMc= , GET\n \n application/json\n 2019-02-25T10:09:57Z\n x-opensearch-nonce:1551089397451704\n /v3/openapi/apps/app_schema_demo/search?fetch_fields=name&query=query%3Dname%3A%27%E6%96%87%E6%A1%A3%27&&sort%3Did&&config%3Dformat%3Afulljson 注意: 请求Header中参数值需与签名方法中对应参数值保持一致 可用以下方法计算签名(Signature) 以 hash_hmac 和 base64_encode 编码生成加密值作为Signature python3 示例代码: import hmac import base64 signature_string = '\n'.join(['GET', '', 'application/json', '2019-02-25T10:09:57Z', 'x-opensearch-nonce:1551089397451704', '/v3/openapi/apps/app_schema_demo/search?fetch_fields=name&query=query%3Dname%3A%27%E6%96%87%E6%A1%A3%27&&sort%3Did&&config%3Dformat%3Afulljson']) signature_hmac = hmac.new('R0OGKsMj0etgyA9nZM5ykhMqHXBfKG'.encode('utf-8'), signature_string.encode('utf-8'), 'sha1') signature = base64.b64encode(signature_hmac.digest()) 假如AccessKeySecret值为 R0OGKsMj0etgyA9nZM5ykhMqHXBfKG 那么通过上面的签名方法构造出来的签名值为 1P7tfEh+CU5kFYRXzZ14kkJUAMc= 构建请求串 请求串 = host + CanonicalizedResource 需在 HTTP 请求 Header 头信息中增加 Authorization(授权)来包含签名(Signature)信息,表明该请求已被授权,同时Header中也需要包含上面提到的这些相关的请求Header。(host为应用访问API地址) 最终search查询请求串 http://host/v3/openapi/apps/app_schema_demo/search?fetch_fields=name&query=query%3Dname%3A%27%E6%96%87%E6%A1%A3%27&&sort%3Did&&config%3Dformat%3Afulljson 最终suggest查询请求串 http://host/v3/openapi/apps/app_schema_demo/suggest/suggest/search?query=%E6%A0%87%E9%A2%98&hits=10 最终查询指定应用信息查询请求串,下面最后一部分为“appid”值,假设为120001234该值,替换后如下所示,该查询请求也需包含Authorization授权签名参数(无需指定查询参数) http://host/v3/openapi/apps/120001234 最终推送数据请求串,此处推送数据需放在body体中 http://host/v3/openapi/apps/app_schema_demo/tab/actions/bulk v3API签名Demo 目前已对外公开 v3版官方Java SDK 和 PHP SDK,且PHP SDK已包含v3API签名过程实现源码,直接调用这些方法即可使用,也可参考 PHP SDK 签名实现过程源码,或参考本文档v3API签名过程来实现其它语言SDK。 因目前OpenSearch官方,没有正式对外提供官方的 python版 和 C#版 SDK,为方便用户参考实现该文档描述签名过程,此处提供 python及C#版查询和推送签名Demo,以供用户参考实现本文档签名操作。 注意: 此处提供 Demo 仅供参考,后续用户参考此 Demo 实现的 SDK 由用户自己维护。

保持可爱mmm 2020-03-26 21:56:35 0 浏览量 回答数 0

问题

V3版API 签名机制是怎样的?

轩墨 2019-12-01 20:57:42 1487 浏览量 回答数 0

问题

【javascript学习全家桶】934道javascript热门问题,阿里百位技术专家答疑解惑

管理贝贝 2019-12-01 20:07:22 6202 浏览量 回答数 1

问题

手把手学IOT服务端API编程[10、保存设备属性][step by step ALI-IOT-SERVER-API]

洵云 2019-12-01 20:55:35 1368 浏览量 回答数 0

问题

手把手学IOT服务端API编程[9、批量获取设备状态][step by step ALI-IOT-SERVER-API]

洵云 2019-12-01 22:08:40 1325 浏览量 回答数 0

回答

各语言普通公钥方式sdk内签名生成sign值及各语言回调数据验签示例代码. 开放平台SDK封装了同步返回响应参数的验签方法,只需在创建DefaultAlipayClient对象进行初始化,设置请求网关(gateway),应用id(app_id),应用私钥(private_key),编码格式(charset),支付宝公钥(alipay_public_key),签名类型(sign_type)即可,同步返回响应参数报文时会自动进行验签。 注:本文示例代码仅供测试参考 java语言: 签名方法: //请求的待签名字符串(已升序排序处理) String content = "app_id=201****222&biz_content={"out_trade_no":"20190401144352106451724","total_amount":"0.01","subject":"土豪机","timeout_express":"10m","qr_code_timeout_express":"2m","store_id":"HK001"}&charset=UTF-8&format=json&method=alipay.trade.precreate&notify_url=http://notify.dengw.online/do/6e5e3bd0-c2c5-4565-bcfd-bf57ea822672&sign_type=RSA2&timestamp=2019-04-01 14:43:53&version=1.0"; //私钥 String privateKey=""; //编码格式 String charset="utf-8"; //签名方式 String sign_type="RSA2"; //签名方法 String sign=AlipaySignature.rsaSign(content, privateKey, charset,sign_type); System.out.println("sign:"+ sign); 验签方法: 异步同步通知数据验签: //回调的待验签字符串 String resultInfo = "buyer_id=20842&total_amount=0.01&body=试™_no=20190329941025940236&notify_time=2019-03-29 19:42:04&subject=**电脑网站支付&sign_type=RSA2&charset=UTF-8&auth_app_id=201222&notify_type=trade_status_sync&invoice_amount=0.01&out_trade_no=20190329ygyg45484544100003™_status=TRADE_SUCCESS&gmt_payment=2019-03-29 19:42:03&version=1.0&point_amount=0.00&sign=LDDUIGQmc+1qNtk3oyoAKVeMUKTngdX3ZjVeZOK0EjiPDJ/+Nk+0WSqcE6J7/5xb96Z/vP0yY3pVhZUiFVJ1G45/ys/HAleHh+EERZ1lkCkule1sSyaGFTKQGKx4uHpTyqIgRB1bouf19RPbSx1EkA0VkCarSy9G/OEG5Qmg8UdL2dRulMhlbOHS7tdMJJycDA8vOspOUMeQmk/H6IK9R2Kou5hN2T3KR1GWLYFK+z1jeZhQB3q52lZynO0OFjSzU4aQUBMW5QskQppBYd/ghtY/2YP+2H6YVGNgVmaheZMQ3PVTBALEV+8rZa91salH9DkKN2UCYGvNSNDT1VGCTQ==&gmt_create=2019-03-29 19:42:00&buyer_pay_amount=0.01&receipt_amount=0.01&fund_bill_list=[{"amount":"0.01","fundChannel":"PCREDIT"}]&seller_id=208***5&app_id=2014100*22&notify_id=201903290022219420408"; //编码格式 String charset="utf-8"; //支付宝公钥 String publicKey=""; //签名方式 String sign_type="RSA2"; //对待签名字符串数据通过&进行拆分 String [] temp = resultInfo.split("&"); LinkedHashMap<String, String> map = new LinkedHashMap<String, String>(); //把拆分数据放在map集合内 for (int i = 0; i < temp.length; i++) { String[] arr = temp[i].split("=", 2); //通过"="号分割成2个数据 String[] tempAagin = new String[arr.length]; //再开辟一个数组用来接收分割后的数据 for (int j = 0; j < arr.length; j++) { tempAagin[j] = arr[j]; } map.put(tempAagin[0], tempAagin[1]); } System.out.println(map); //验签方法 boolean signVerified = AlipaySignature.rsaCheckV1(map,publicKey,charset,sign_type); if(signVerified){ // TODO 验签成功后 System.out.println("success"); }else{ System.out.println("fail"); } 生活号响应返回的数据验签: //回调的待验签字符串 String resultInfo = "biz_content= &sign=PuVStqgcU6cQw1bNx09+Dd7/5UkWXTuOKYvRKQSUSYnjR/fU2xYbat1x2bhHb2qScTxH71toVHaQq/he6FJQskTAaSrnFg+Du/WMz62UpalHA62iVQFlsr2j9mmPtOZoTqzG1debdnxOiN8O2joz/iHXluzfIPay+92I4XKALG8kCyn6Smpu40BNzJxmFqkzc4VmBONNesRS9FnN5C/X34J8D4Eo98sbD7BrUTege5Z2FOujma26MyT4o3A2zPGpP3f8KZXxwF7Xl4frV5IuDm6OHUnnhOfzn3cW+eA4Q6Jm0CA19Ez/ejub2lMGpw7GOPGIFae74AKRvdQDnD9hQQ==&sign_type=RSA2&service=alipay.service.check&charset=GBK"; //编码格式,生活号默认接收的数据都是gbk格式的 String charset="GBK"; //支付宝公钥 String publicKey=""; //签名方式 String sign_type="RSA2"; //对待签名字符串数据通过&进行拆分 String [] temp = resultInfo.split("&"); LinkedHashMap<String, String> map = new LinkedHashMap<String, String>(); //把拆分数据放在map集合内 for (int i = 0; i < temp.length; i++) { String[] arr = temp[i].split("=", 2); //通过"="号分割成2个数据 String[] tempAagin = new String[arr.length]; //再开辟一个数组用来接收分割后的数据 for (int j = 0; j < arr.length; j++) { tempAagin[j] = arr[j]; } map.put(tempAagin[0], tempAagin[1]); } System.out.println(map); //验签方法 boolean signVerified = AlipaySignature.rsaCheckV2(map,publicKey,charset,sign_type); if(signVerified){ // TODO 验签成功后 System.out.println("success"); }else{ System.out.println("fail"); } 同步响应数据验签: //响应的待验签字符串 String resultInfo = "{"code":"10000","msg":"Success","app_id":"2014115","auth_app_id":"2014175","charset":"utf-8","timestamp":"2019-04-01 14:33:01","out_trade_no":"0401022927-9449","total_amount":"0.01","trade_no":"2019040122751034473539","seller_id":"20856*5"}"; //响应数据返回的sign值 String sign=""; //编码格式 String charset="utf-8"; //支付宝公钥 String publicKey=""; //签名方式 String sign_type="RSA2"; //验签方法 boolean signVerified= AlipaySignature.rsaCheck(resultInfo, sign, publicKey, charset, sign_type); if(signVerified){ // TODO 验签成功后 System.out.println("success"); }else{ System.out.println("fail"); } php语言: 签名方法: $aop = new AopClient(); //私钥 $privatekey=""; //签名方式 $signType="RSA2"; //待签名字符串 $data="app_id=201410***2&biz_content={"out_trade_no":"20190401144352106451724","total_amount":"0.01","subject":"土豪机","timeout_express":"10m","qr_code_timeout_express":"2m","store_id":"HK001"}&charset=UTF-8&format=json&method=alipay.trade.precreate&notify_url=http://notify.dengw.online/do/***&sign_type=RSA2&timestamp=2019-04-01 14:43:53&version=1.0"; //sdk内封装的签名方法 $sign=$aop->alonersaSign($data,$privatekey,$signType,false); echo "sign:".$sign; 验签方法: 异步同步通知数据验签方法: $aop = new AopClient (); //支付宝公钥赋值 $aop->alipayrsaPublicKey=""; //待签名字符串 $_POST="buyer_id=2088042&total_amount=0.01&body=煜雨电脑网站测试™_no=2019032922001481941025940236&notify_time=2019-03-29 19:42:04&subject=煜雨测试电脑网站支付&sign_type=RSA2&charset=UTF-8&auth_app_id=20122&notify_type=trade_status_sync&invoice_amount=0.01&out_trade_no=20190329ygyg45484544100003™_status=TRADE_SUCCESS&gmt_payment=2019-03-29 19:42:03&version=1.0&point_amount=0.00&sign=LDDUIGQmc+1qNtk3oyoAKVeMUKTngdX3ZjVeZOK0EjiPDJ/+Nk+0WSqcE6J7/5xb96Z/vP0yY3pVhZUiFVJ1G45/ys/HAleHh+EERZ1lkCkule1sSyaGFTKQGKx4uHpTyqIgRB1bouf19RPbSx1EkA0VkCarSy9G/OEG5Qmg8UdL2dRulMhlbOHS7tdMJJycDA8vOspOUMeQmk/H6IK9R2Kou5hN2T3KR1GWLYFK+z1jeZhQB3q52lZynO0OFjSzU4aQUBMW5QskQppBYd/ghtY/2YP+2H6YVGNgVmaheZMQ3PVTBALEV+8rZa91salH9DkKN2UCYGvNSNDT1VGCTQ==&gmt_create=2019-03-29 19:42:00&buyer_pay_amount=0.01&receipt_amount=0.01&fund_bill_list=[{"amount":"0.01","fundChannel":"PCREDIT"}]&seller_id=2088500**&app_id=20141***2&notify_id=2019032900222194204081941005192208"; //签名方式 $sign_type="RSA2"; //把字符串通过&符号拆分成数组 $data = explode('&', $_POST); $params = array(); //遍历数组 foreach ($data as $param) { $item = explode('=', $param,"2"); $params[$item[0]] = $item[1]; } //输出拆分后的数据 //print_r($params); //验签代码 $flag = $aop->rsaCheckV1($params, null, $sign_type); //输出验签结果 //echo $flag; if ($flag) { echo "success"; } else { echo "fail"; } 生活号响应返回的数据验签: $aop = new AopClient (); //支付宝公钥赋值 $aop->alipayrsaPublicKey=""; //待签名字符串 $_POST="biz_content= &sign=PuVStqgcU6cQw1bNx09+Dd7/5UkWXTuOKYvRKQSUSYnjR/fU2xYbat1x2bhHb2qScTxH71toVHaQq/he6FJQskTAaSrnFg+Du/WMz62UpalHA62iVQFlsr2j9mmPtOZoTqzG1debdnxOiN8O2joz/iHXluzfIPay+92I4XKALG8kCyn6Smpu40BNzJxmFqkzc4VmBONNesRS9FnN5C/X34J8D4Eo98sbD7BrUTege5Z2FOujma26MyT4o3A2zPGpP3f8KZXxwF7Xl4frV5IuDm6OHUnnhOfzn3cW+eA4Q6Jm0CA19Ez/ejub2lMGpw7GOPGIFae74AKRvdQDnD9hQQ==&sign_type=RSA2&service=alipay.service.check&charset=GBK"; //签名方式 $sign_type="RSA2"; //把字符串通过&符号拆分成数组 $data = explode('&', $_POST); //输出数据 //echo json_encode($data,JSON_UNESCAPED_UNICODE); $params = array(); //遍历数组 foreach ($data as $param) { $item = explode('=', $param,'2'); $params[$item[0]] = $item[1]; } //输出拆分后的数组集合 //echo json_encode($params,JSON_UNESCAPED_UNICODE); //验签代码 $flag = $aop->rsaCheckV2($params, null, $sign_type); if ($flag) { echo "success"; } else { echo "fail"; } 同步响应数据验签: $aop = new AopClient (); //支付宝公钥赋值 $aop->alipayrsaPublicKey=""; //待签名字符串 $_POST="{"code":"10000","msg":"Success","app_id":"2075","auth_app_id":"20145","charset":"utf-8","timestamp":"2019-04-01 14:33:01","out_trade_no":"0401022927-9449","total_amount":"0.01","trade_no":"201904012200145675**39","seller_id":"20****5"}"; //sign值 $sign=""; //签名方式 $sign_type="RSA2"; //验签代码 $flag = $aop->verify($_POST, $sign,null,$sign_type); if ($flag) { echo "success"; } else { echo "fail"; } .net语言: 签名方法: //请求的待签名字符串(已升序排序处理) string content = "app_id=201*****2&biz_content={"out_trade_no":"2019040145454106451724","total_amount":"0.01","subject":"****","timeout_express":"10m","qr_code_timeout_express":"2m","store_id":"HK001"}&charset=UTF-8&format=json&method=alipay.trade.precreate&notify_url=http://notify.dengw.online/do/6e5e3bd0-c2c5-4565-bcfd-bf57ea822672&sign_type=RSA2&timestamp=2019-04-01 14:43:53&version=1.0"; //应用私钥:PKCS1格式 string privateKey = ""; //签名方法 string sign = AlipaySignature.RSASign(content, privateKey, "UTF-8", "RSA2", false); Response.Write("sign:" + sign); 验签方法: 异步同步通知数据验签: //异步通知参数 string str = "buyer_id=208****&total_amount=0.01&body=煜雨电脑网站测试™_no=2019032922001481941025940236&notify_time=2019-03-29 19:42:04&subject=煜雨测试电脑网站支付&sign_type=RSA2&charset=UTF-8&auth_app_id=20141009****&notify_type=trade_status_sync&invoice_amount=0.01&out_trade_no=20190329ygyg45484544100003™_status=TRADE_SUCCESS&gmt_payment=2019-03-29 19:42:03&version=1.0&point_amount=0.00&sign=LDDUIGQmc+1qNtk3oyoAKVeMUKTngdX3ZjVeZOK0EjiPDJ/+Nk+0WSqcE6J7/5xb96Z/vP0yY3pVhZUiFVJ1G45/ys/HAleHh+EERZ1lkCkule1sSyaGFTKQGKx4uHpTyqIgRB1bouf19RPbSx1EkA0VkCarSy9G/OEG5Qmg8UdL2dRulMhlbOHS7tdMJJycDA8vOspOUMeQmk/H6IK9R2Kou5hN2T3KR1GWLYFK+z1jeZhQB3q52lZynO0OFjSzU4aQUBMW5QskQppBYd/ghtY/2YP+2H6YVGNgVmaheZMQ3PVTBALEV+8rZa91salH9DkKN2UCYGvNSNDT1VGCTQ==&gmt_create=2019-03-29 19:42:00&buyer_pay_amount=0.01&receipt_amount=0.01&fund_bill_list=[{"amount":"0.01","fundChannel":"PCREDIT"}]&seller_id=208850*****&app_id=20141*****2&notify_id=2019032900222194204081941005192208"; string charset ="utf-8"; string sign_type = "RSA2"; var dics = new Dictionary<string, string>(); var rearray = str.Split('&'); foreach (var a in rearray) { var array = a.IndexOf('='); dics.Add(a.Substring(0, array), a.Substring(array+1)); Response.Write(a + ""); } //支付宝公钥 string alipaypublicKey = ""; //验签方法 bool flag = AlipaySignature.RSACheckV1(dics, alipaypublicKey, charset, sign_type, false); Response.Write(flag); 生活号响应返回的数据验签: //异步通知参数 string str = "biz_content= &sign=PuVStqgcU6cQw1bNx09+Dd7/5UkWXTuOKYvRKQSUSYnjR/fU2xYbat1x2bhHb2qScTxH71toVHaQq/he6FJQskTAaSrnFg+Du/WMz62UpalHA62iVQFlsr2j9mmPtOZoTqzG1debdnxOiN8O2joz/iHXluzfIPay+92I4XKALG8kCyn6Smpu40BNzJxmFqkzc4VmBONNesRS9FnN5C/X34J8D4Eo98sbD7BrUTege5Z2FOujma26MyT4o3A2zPGpP3f8KZXxwF7Xl4frV5IuDm6OHUnnhOfzn3cW+eA4Q6Jm0CA19Ez/ejub2lMGpw7GOPGIFae74AKRvdQDnD9hQQ==&sign_type=RSA2&service=alipay.service.check&charset=GBK"; var dics = new Dictionary<string, string>(); var rearray = str.Split('&'); foreach (var a in rearray) { var array = a.IndexOf('='); dics.Add(a.Substring(0, array), a.Substring(array+1)); Response.Write(a + ""); } //支付宝公钥 string alipaypublicKey = ""; //验签方法 bool flag = AlipaySignature.RSACheckV2(dics, alipaypublicKey, "UTF-8","RSA2", false); Response.Write(flag); 同步响应数据验签: //响应的待验签字符串 string signContent = "{\"code\":\"10000\",\"msg\":\"Success\",\"app_id\":\"20141***5\",\"auth_app_id\":\"201411*****\",\"charset\":\"utf-8\",\"timestamp\":\"2019-04-01 14:33:01\",\"out_trade_no\":\"0401022927-9449\",\"total_amount\":\"0.01\",\"trade_no\":\"2019040122001456**9\",\"seller_id\":\"20***16245***\"}"; //响应数据返回的sign值 string sign = ""; //支付宝公钥 string alipaypublicKey = ""; //验签方法 bool flag = AlipaySignature.RSACheckContent(signContent, sign, alipaypublicKey, "UTF-8", "RSA2", false); Response.Write(flag); python语言: 签名方法: #!/usr/bin/env python -- coding: utf-8 -- import urllib from alipay.aop.api.util.SignatureUtils import * 请求的待签名字符串(已升序排序处理) content = "app_id=20***2&biz_content={"out_trade_no":"20190401144352106451724","total_amount":"0.01","subject":"土豪机","timeout_express":"10m","qr_code_timeout_express":"2m","store_id":"HK001"}&charset=UTF-8&format=json&method=alipay.trade.precreate&notify_url=http://notify.dengw.online/do/6e5e3bd0-c2c5-4565-bcfd-bf57ea822672&sign_type=RSA2&timestamp=2019-04-01 14:43:53&version=1.0" 私钥 privateKey = "" 编码格式 charset = "utf-8" 请求网关地址 gateway = "https://openapi.alipay.com/gateway.do" RSA2签名方式 sign = sign_with_rsa2(privateKey, content, charset) RSA签名方式 sign = sign_with_rsa(privateKey, content, charset) 输出sign值 print sign 验签方法: 异步同步通知数据验签: #!/usr/bin/env python -- coding: utf-8 -- from alipay.aop.api.util.SignatureUtils import verify_with_rsa 支付宝公钥 alipay_public_key = "" 待签名字符串需要做升序处理,且去除sign和sign_type message = "app_id=2012&auth_app_id=20142&body=煜雨电脑网站测试&buyer_id=2088022*****2&buyer_pay_amount=0.01&charset=UTF-8&fund_bill_list=[{"amount":"0.01","fundChannel":"PCREDIT"}]&gmt_create=2019-03-29 19:42:00&gmt_payment=2019-03-29 19:42:03&invoice_amount=0.01&notify_id=2019032900222194204081941005192208&notify_time=2019-03-29 19:42:04&notify_type=trade_status_sync&out_trade_no=20190329ygyg45484544100003&point_amount=0.00&receipt_amount=0.01&seller_id=20*******5&subject=煜雨测试电脑网站支付&total_amount=0.01™_no=2019032922001481941025940236™_status=TRADE_SUCCESS&version=1.0" 返回的sign值 sign = "" 签名方法 flag = verify_with_rsa(alipay_public_key, message, sign) 输出验签结果 print flag 生活号响应返回的数据验签: #!/usr/bin/env python -- coding: utf-8 -- from alipay.aop.api.util.SignatureUtils import verify_with_rsa 支付宝公钥 alipay_public_key = "" 待签名字符串需要做升序处理,去除sign message = "biz_content= &charset=GBK&service=alipay.service.check&sign_type=RSA2" 返回的sign值 sign = "" 签名方法 flag = verify_with_rsa(alipay_public_key, message, sign) 输出验签结果 print flag 同步响应数据验签: #!/usr/bin/env python -- coding: utf-8 -- from alipay.aop.api.util.SignatureUtils import verify_with_rsa 支付宝公钥 alipay_public_key = "" 待签名字符串大框号内的值 message = "{"code":"10000","msg":"Success","app_id":"201***5","auth_app_id":"201***","charset":"utf-8","timestamp":"2019-04-01 14:33:01","out_trade_no":"0401022927-9449","total_amount":"0.01","trade_no":"2019040122001456751034473539","seller_id":"2088***5"}" 返回的sign值 sign = "" 签名方法 flag = verify_with_rsa(alipay_public_key, message, sign) 输出验签结果 print flag 更多详见【签名验签文档说明】。

保持可爱mmm 2020-05-05 16:49:52 0 浏览量 回答数 0

问题

【阿里云产品公测】简单日志服务SLS使用评测含教程

mr_wid 2019-12-01 21:08:11 36639 浏览量 回答数 20

回答

详细解答可以参考官方帮助文档 用户只需要在发送给OSS的请求中携带相应的Callback参数,即能实现回调。 现在支持CallBack的API 接口有:PutObject、PostObject、CompleteMultipartUpload。 构造CallBack参数 CallBack参数是由一段经过base64编码的Json字串,用户关键需要指定请求回调的服务器URL(callbackUrl)以及回调的内容(callbackBody)。详细的Json字段如下: 字段 含义 选项 callbackUrl 文件上传成功后OSS向此url发送回调请求,请求方法为POST,body为callbackBody指定的内容。正常情况下,该url需要响应“HTTP/1.1 200 OK”,body必须为JSON格式,响应头Content-Length必须为合法的值,且不超过3MB。 支持同时配置最多5个url,以”;”分割。OSS会依次发送请求直到第一个返回成功为止。 如果没有配置或者值为空则认为没有配置callback。 支持HTTPS地址。 为了保证正确处理中文等情况,callbackUrl需做url编码处理,比如http://example.com/中文.php?key=value&中文名称=中文值 需要编码成 http://example.com/%E4%B8%AD%E6%96%87.php?key=value&%E4%B8%AD%E6%96%87%E5%90%8D%E7%A7%B0=%E4%B8%AD%E6%96%87%E5%80%BC 必选项 callbackHost 发起回调请求时Host头的值,只有在设置了callbackUrl时才有效。 如果没有配置 callbckHost,则会解析callbackUrl中的url并将解析出的host填充到callbackHost中 可选项 callbackBody 发起回调时请求body的值,例如:key=$(key)&etag=$(etag)&my_var=$(x:my_var)。 支持OSS系统变量、自定义变量和常量,支持的系统变量如下表所示 。自定义变量的支持方式在PutObject和CompleteMultipart中是通过callback-var来传递,在PostObject中则是将各个变量通过表单域来传递。 必选项 callbackBodyType 发起回调请求的Content-Type,支持application/x-www-form-urlencoded和application/json,默认为前者。 如果为application/x-www-form-urlencoded,则callbackBody中的变量将会被经过url编码的值替换掉,如果为application/json,则会按照json格式替换其中的变量。 可选项 示例json串如下 { "callbackUrl":"121.101.166.30/test.php", "callbackHost":"oss-cn-hangzhou.aliyuncs.com", "callbackBody":"{\"mimeType\":${mimeType},\"size\":${size}}", "callbackBodyType":"application/json" } { "callbackUrl":"121.43.113.8:23456/index.html", "callbackBody":"bucket=${bucket}&object=${object}&etag=${etag}&size=${size}&mimeType=${mimeType}&imageInfo.height=${imageInfo.height}&imageInfo.width=${imageInfo.width}&imageInfo.format=${imageInfo.format}&my_var=${x:my_var}" } 其中callbackBody中可以设置的系统变量有,其中imageInfo针对于图片格式,如果为非图片格式都为空: 系统变量 含义 bucket bucket object object etag 文件的etag,即返回给用户的etag字段 size object大小,CompleteMultipartUpload时为整个object的大小 mimeType 资源类型,如jpeg图片的资源类型为image/jpeg imageInfo.height 图片高度 imageInfo.width 图片宽度 imageInfo.format 图片格式,如jpg、png等 自定义参数 用户可以通过callback-var参数来配置自定义参数。 自定义参数是一个Key-Value的Map,用户可以配置自己需要的参数到这个Map。在OSS发起POST回调请求的时候,会将这些参数和上一节所述的系统参数一起放在POST请求的body中以方便接收回调方获取。 构造自定义参数的方法和callback参数的方法是一样的,也是以json格式来传递。该json字符串就是一个包含所有自定义参数的Key-Value的Map。 说明 用户自定义参数的Key一定要以x:开头,且必须为小写。否则OSS会返回错误。 假定用户需要设定两个自定义的参数分别为x:var1和x:var2,对应的值分别为value1和value2,那么构造出来的json格式如下: { "x:var1":"value1", "x:var2":"value2" } 构造回调请求 构造完成上述的callback和callback-var两个参数之后,一共有三种方式传给OSS。其中callback为必填参数,callback-var为可选参数,如果没有自定义参数的话可以不用添加callback-var字段。这三种方式如下: 在URL中携带参数。 在Header中携带参数。 在POST请求的body中使用表单域来携带参数。 说明 在使用POST请求上传Object的时候只能使用这种方式来指定回调参数。 这三种方式只能同时使用其中一种,否则OSS会返回InvalidArgument错误。 要将参数附加到OSS的请求中,首先要将上文构造的json字符串使用base64编码,然后按照如下的方法附加到OSS的请求中: 如果在URL中携带参数。把callback=[CallBack]或者callback-var=[CallBackVar]作为一个url参数带入请求发送。计算签名CanonicalizedResource时 ,将callback或者callback-var当做一个sub-resource计算在内 如果在Header中携带参数。把x-oss-callback=[CallBack]或者x-oss-callback-var=[CallBackVar]作为一个head带入请求发送。在计算签名CanonicalizedOSSHeaders时,将x-oss-callback-var和x-oss-callback计算在内。如下示例:PUT /test.txt HTTP/1.1 Host: callback-test.oss-test.aliyun-inc.com Accept-ncoding: identity Content-Length: 5 x-oss-callback-var: eyJ4Om15X3ZhciI6ImZvci1jYWxsYmFjay10ZXN0In0= User-Agent: aliyun-sdk-python/0.4.0 (Linux/2.6.32-220.23.2.ali1089.el5.x86_64/x86_64;2.5.4) x-oss-callback: eyJjYWxsYmFja1VybCI6IjEyMS40My4xMTMuODoyMzQ1Ni9pbmRleC5odG1sIiwgICJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mZXRhZz0ke2V0YWd9JnNpemU9JHtzaXplfSZtaW1lVHlwZT0ke21pbWVUeXBlfSZpbWFnZUluZm8uaGVpZ2h0PSR7aW1hZ2VJbmZvLmhlaWdodH0maW1hZ2VJbmZvLndpZHRoPSR7aW1hZ2VJbmZvLndpZHRofSZpbWFnZUluZm8uZm9ybWF0PSR7aW1hZ2VJbmZvLmZvcm1hdH0mbXlfdmFyPSR7eDpteV92YXJ9In0= Host: callback-test.oss-test.aliyun-inc.com Expect: 100-Continue Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: text/plain Authorization: OSS mlepou3zr4u7b14:5a74vhd4UXpmyuudV14Kaen5cY4= Test 如果需要在POST上传Object的时候附带回调参数会稍微复杂一点,callback参数要使用独立的表单域来附加,如下面的示例:--9431149156168 Content-Disposition: form-data; name="callback" eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkmdGFibGU9JHt4OnRhYmxlfSIsImNhbGxiYWNrQm9keVR5cGUiOiJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQifQ==如果拥有自定义参数的话,不能直接将callback-var参数直接附加到表单域中,每个自定义的参数都需要使用独立的表单域来附加,举个例子,如果用户的自定义参数的json为{ "x:var1":"value1", "x:var2":"value2" }那么POST请求的表单域应该如下:--9431149156168 Content-Disposition: form-data; name="callback" eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkmdGFibGU9JHt4OnRhYmxlfSIsImNhbGxiYWNrQm9keVR5cGUiOiJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQifQ== --9431149156168 Content-Disposition: form-data; name="x:var1" value1 --9431149156168 Content-Disposition: form-data; name="x:var2" value2同时可以在policy中添加callback条件(如果不添加callback,则不对该参数做上传验证)如:{ "expiration": "2014-12-01T12:00:00.000Z", "conditions": [ {"bucket": "johnsmith" }, {"callback": "eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkiLCJjYWxsYmFja0JvZHlUeXBlIjoiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIn0="}, ["starts-with", "$key", "user/eric/"], ] } 发起回调请求 如果文件上传成功,OSS会根据用户的请求中的callback参数和自定义参数(callback-var参数),将特定内容以POST方式发送给应用服务器。 POST /index.html HTTP/1.0 Host: 121.43.113.8 Connection: close Content-Length: 181 Content-Type: application/x-www-form-urlencoded User-Agent: ehttp-client/0.0.1 bucket=callback-test&object=test.txt&etag=D8E8FCA2DC0F896FD7CB4CB0031BA249&size=5&mimeType=text%2Fplain&imageInfo.height=&imageInfo.width=&imageInfo.format=&x:var1=for-callback-test 返回回调结果 比如应用服务器端返回的回应请求为: HTTP/1.0 200 OK Server: BaseHTTP/0.3 Python/2.7.6 Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: application/json Content-Length: 9 {"a":"b"} 返回上传结果 再给客户端的内容为: HTTP/1.1 200 OK Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: application/json Content-Length: 9 Connection: keep-alive ETag: "D8E8FCA2DC0F896FD7CB4CB0031BA249" Server: AliyunOSS x-oss-bucket-version: 1442231779 x-oss-request-id: 55F6BF87207FB30F2640C548 {"a":"b"} 需要注意的是,如果类似CompleteMultipartUpload这样的请求,在返回请求本身body中存在内容(如XMl格式的信息),使用上传回调功能后会覆盖原有的body的内容如{"a":"b"},希望对此处做好判断处理。 回调签名 用户设置callback参数后,OSS将按照用户设置的callbackUrl发送POST回调请求给用户的应用服务器。应用服务器收到回调请求之后,如果希望验证回调请求确实是由OSS发起的话,那么可以通过在回调中带上签名来验证OSS的身份。 生成签名 签名在OSS端发生,采用RSA非对称方式签名,私钥加密的过程为:authorization = base64_encode(rsa_sign(private_key, url_decode(path) + query_string + ‘\n’ + body, md5)) 说明 其中private_key为私钥,只有oss知晓,path为回调请求的资源路径,query_string为查询字符串,body为回调的消息体,所以签名过程由以下几步组成: 获取待签名字符串:资源路径经过url解码后,加上原始的查询字符串,加上一个回车符,加上回调消息体 RSA签名:使用秘钥对待签名字符串进行签名,签名的hash函数为md5 将签名后的结果做base64编码,得到最终的签名,签名放在回调请求的authorization头中 如下例:POST /index.php?id=1&index=2 HTTP/1.0 Host: 121.43.113.8 Connection: close Content-Length: 18 authorization: kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA== Content-Type: application/x-www-form-urlencoded User-Agent: ehttp-client/0.0.1 x-oss-pub-key-url: aHR0cDovL2dvc3NwdWJsaWMuYWxpY2RuLmNvbS9jYWxsYmFja19wdWJfa2V5X3YxLnBlbQ== bucket=yonghu-testpath为/index.php,query_string为?id=1&index=2,body为bucket=yonghu-test,最终签名结果为kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA== 验证签名 验证签名的过程即为签名的逆过程,由应用服务器验证,过程如下:Result = rsa_verify(public_key, md5(url_decode(path) + query_string + ‘\n’ + body), base64_decode(authorization))字段的含义与签名过程中描述相同,其中public_key为公钥, authorization为回调头中的签名,整个验证签名的过程分为以下几步: 回调请求的x-oss-pub-key-url头保存的是公钥的url地址的base64编码,因此需要对其做base64解码后获取到公钥,即public_key = urlopen(base64_decode(x-oss-pub-key-url头的值))这里需要注意,用户需要校验x-oss-pub-key-url头的值必须以http://gosspublic.alicdn.com/或者https://gosspublic.alicdn.com/开头,目的是为了保证这个publickey是由OSS颁发的。 获取base64解码后的签名signature = base64_decode(authorization头的值) 获取待签名字符串,方法与签名一致sign_str = url_decode(path) + query_string + ‘\n’ + body 验证签名result = rsa_verify(public_key, md5(sign_str), signature) 以上例为例: 获取到公钥的url地址,即aHR0cDovL2dvc3NwdWJsaWMuYWxpY2RuLmNvbS9jYWxsYmFja19wdWJfa2V5X3YxLnBlbQ==经过base64解码后得到http://gosspublic.alicdn.com/callback_pub_key_v1.pem 签名头kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA==做base64解码(由于为非打印字符,无法显示出解码后的结果) 获取待签名字符串,即url_decode(“index.php”) + “?id=1&index=2” + “\n” + “bucket=yonghu-test”,并做md5 验证签名 应用服务器示例 以下为一段python示例,演示了一个简单的应用服务器,主要是说明验证签名的方法,此示例需要安装M2Crypto库import httplib import base64 import md5 import urllib2 from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer from M2Crypto import RSA from M2Crypto import BIO def get_local_ip(): try: csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) csock.connect(('8.8.8.8', 80)) (addr, port) = csock.getsockname() csock.close() return addr except socket.error: return "" class MyHTTPRequestHandler(BaseHTTPRequestHandler): ''' def log_message(self, format, *args): return ''' def do_POST(self): #get public key pub_key_url = '' try: pub_key_url_base64 = self.headers['x-oss-pub-key-url'] pub_key_url = pub_key_url_base64.decode('base64') if not pub_key_url.startswith("http://gosspublic.alicdn.com/") and not pub_key_url.startswith("https://gosspublic.alicdn.com/"): self.send_response(400) self.end_headers() return url_reader = urllib2.urlopen(pub_key_url) #you can cache it pub_key = url_reader.read() except: print 'pub_key_url : ' + pub_key_url print 'Get pub key failed!' self.send_response(400) self.end_headers() return #get authorization authorization_base64 = self.headers['authorization'] authorization = authorization_base64.decode('base64') #get callback body content_length = self.headers['content-length'] callback_body = self.rfile.read(int(content_length)) #compose authorization string auth_str = '' pos = self.path.find('?') if -1 == pos: auth_str = urllib2.unquote(self.path) + '\n' + callback_body else: auth_str = urllib2.unquote(self.path[0:pos]) + self.path[pos:] + '\n' + callback_body print auth_str #verify authorization auth_md5 = md5.new(auth_str).digest() bio = BIO.MemoryBuffer(pub_key) rsa_pub = RSA.load_pub_key_bio(bio) try: result = rsa_pub.verify(auth_md5, authorization, 'md5') except: result = False if not result: print 'Authorization verify failed!' print 'Public key : %s' % (pub_key) print 'Auth string : %s' % (auth_str) self.send_response(400) self.end_headers() return #do something accoding to callback_body #response to OSS resp_body = '{"Status":"OK"}' self.send_response(200) self.send_header('Content-Type', 'application/json') self.send_header('Content-Length', str(len(resp_body))) self.end_headers() self.wfile.write(resp_body) class MyHTTPServer(HTTPServer): def __init__(self, host, port): HTTPServer.__init__(self, (host, port), MyHTTPRequestHandler) if '__main__' == __name__: server_ip = get_local_ip() server_port = 23451 server = MyHTTPServer(server_ip, server_port) server.serve_forever()其它语言实现的应用服务器如下: Java版本: 下载地址:点击这里 运行方法:解压包运行java -jar oss-callback-server-demo.jar 9000(9000就运行的端口,可以自己指定) PHP版本: 下载地址:点击这里 运行方法:部署到Apache环境下,因为PHP本身语言的特点,取一些数据头部会依赖于环境。所以可以参考例子根据所在环境修改。 Python版本: 下载地址:点击这里 运行方法:解压包直接运行python callback_app_server.py,运行该程序需要安装rsa的依赖。 C#版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Go版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Go版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Ruby版本: 下载地址:点击这里 运行方法: ruby aliyun_oss_callback_server.rb 特别须知 如果传入的callback或者callback-var不合法,则会返回400错误,错误码为”InvalidArgument”,不合法的情况包括以下几类: PutObject()和CompleteMultipartUpload()接口中url和header同时传入callback(x-oss-callback)或者callback-var(x-oss-callback-var)参数 callback或者callback-var(PostObject()由于没有callback-var参数,因此没有此限制,下同)参数过长(超过5KB) callback或者callback-var没有经过base64编码 callback或者callback-var经过base64解码后不是合法的json格式 callback参数解析后callbackUrl字段包含的url超过限制(5个),或者url中传入的port不合法,比如{"callbackUrl":"10.101.166.30:test", "callbackBody":"test"} callback参数解析后callbackBody字段为空 callback参数解析后callbackBodyType字段的值不是”application/x-www-form-urlencoded”或者”application/json” callback参数解析后callbackBody字段中变量的格式不合法,合法的格式为${var} callback-var参数解析后不是预期的json格式,预期的格式应该为{"x:var1":"value1","x:var2":"value2"...} 如果回调失败,则返回203,错误码为”CallbackFailed”,回调失败只是表示OSS没有收到预期的回调响应,不代表应用服务器没有收到回调请求(比如应用服务器返回的内容不是json格式),另外,此时文件已经成功上传到了OSS 应用服务器返回OSS的响应必须带有Content-Length的Header,Body大小不要超过1MB。 Callback支持的地域 Callback目前支持的地域如下:华北 2(北京)、华东 1(杭州)、华北 1(青岛)、华东 2(上海)、上海金融云、华南 1(深圳)、香港、华北 5(呼和浩特)、华北 3(张家口)、中东东部 1(迪拜)、亚太东北 1(日本)、欧洲中部 1(法兰克福)、亚太东南 1(新加坡)、美国东部 1(弗吉尼亚)、美国西部 1(硅谷)、亚太东南 2 (悉尼)以及亚太东南 3(吉隆坡)。

2019-12-01 23:13:51 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 用户只需要在发送给OSS的请求中携带相应的Callback参数,即能实现回调。 现在支持CallBack的API 接口有:PutObject、PostObject、CompleteMultipartUpload。 构造CallBack参数 CallBack参数是由一段经过base64编码的Json字串,用户关键需要指定请求回调的服务器URL(callbackUrl)以及回调的内容(callbackBody)。详细的Json字段如下: 字段 含义 选项 callbackUrl 文件上传成功后OSS向此url发送回调请求,请求方法为POST,body为callbackBody指定的内容。正常情况下,该url需要响应“HTTP/1.1 200 OK”,body必须为JSON格式,响应头Content-Length必须为合法的值,且不超过3MB。 支持同时配置最多5个url,以”;”分割。OSS会依次发送请求直到第一个返回成功为止。 如果没有配置或者值为空则认为没有配置callback。 支持HTTPS地址。 为了保证正确处理中文等情况,callbackUrl需做url编码处理,比如http://example.com/中文.php?key=value&中文名称=中文值 需要编码成 http://example.com/%E4%B8%AD%E6%96%87.php?key=value&%E4%B8%AD%E6%96%87%E5%90%8D%E7%A7%B0=%E4%B8%AD%E6%96%87%E5%80%BC 必选项 callbackHost 发起回调请求时Host头的值,只有在设置了callbackUrl时才有效。 如果没有配置 callbckHost,则会解析callbackUrl中的url并将解析出的host填充到callbackHost中 可选项 callbackBody 发起回调时请求body的值,例如:key=$(key)&etag=$(etag)&my_var=$(x:my_var)。 支持OSS系统变量、自定义变量和常量,支持的系统变量如下表所示 。自定义变量的支持方式在PutObject和CompleteMultipart中是通过callback-var来传递,在PostObject中则是将各个变量通过表单域来传递。 必选项 callbackBodyType 发起回调请求的Content-Type,支持application/x-www-form-urlencoded和application/json,默认为前者。 如果为application/x-www-form-urlencoded,则callbackBody中的变量将会被经过url编码的值替换掉,如果为application/json,则会按照json格式替换其中的变量。 可选项 示例json串如下 { "callbackUrl":"121.101.166.30/test.php", "callbackHost":"oss-cn-hangzhou.aliyuncs.com", "callbackBody":"{\"mimeType\":${mimeType},\"size\":${size}}", "callbackBodyType":"application/json" } { "callbackUrl":"121.43.113.8:23456/index.html", "callbackBody":"bucket=${bucket}&object=${object}&etag=${etag}&size=${size}&mimeType=${mimeType}&imageInfo.height=${imageInfo.height}&imageInfo.width=${imageInfo.width}&imageInfo.format=${imageInfo.format}&my_var=${x:my_var}" } 其中callbackBody中可以设置的系统变量有,其中imageInfo针对于图片格式,如果为非图片格式都为空: 系统变量 含义 bucket bucket object object etag 文件的etag,即返回给用户的etag字段 size object大小,CompleteMultipartUpload时为整个object的大小 mimeType 资源类型,如jpeg图片的资源类型为image/jpeg imageInfo.height 图片高度 imageInfo.width 图片宽度 imageInfo.format 图片格式,如jpg、png等 自定义参数 用户可以通过callback-var参数来配置自定义参数。 自定义参数是一个Key-Value的Map,用户可以配置自己需要的参数到这个Map。在OSS发起POST回调请求的时候,会将这些参数和上一节所述的系统参数一起放在POST请求的body中以方便接收回调方获取。 构造自定义参数的方法和callback参数的方法是一样的,也是以json格式来传递。该json字符串就是一个包含所有自定义参数的Key-Value的Map。 说明 用户自定义参数的Key一定要以x:开头,且必须为小写。否则OSS会返回错误。 假定用户需要设定两个自定义的参数分别为x:var1和x:var2,对应的值分别为value1和value2,那么构造出来的json格式如下: { "x:var1":"value1", "x:var2":"value2" } 构造回调请求 构造完成上述的callback和callback-var两个参数之后,一共有三种方式传给OSS。其中callback为必填参数,callback-var为可选参数,如果没有自定义参数的话可以不用添加callback-var字段。这三种方式如下: 在URL中携带参数。 在Header中携带参数。 在POST请求的body中使用表单域来携带参数。 说明 在使用POST请求上传Object的时候只能使用这种方式来指定回调参数。 这三种方式只能同时使用其中一种,否则OSS会返回InvalidArgument错误。 要将参数附加到OSS的请求中,首先要将上文构造的json字符串使用base64编码,然后按照如下的方法附加到OSS的请求中: 如果在URL中携带参数。把callback=[CallBack]或者callback-var=[CallBackVar]作为一个url参数带入请求发送。计算签名CanonicalizedResource时 ,将callback或者callback-var当做一个sub-resource计算在内 如果在Header中携带参数。把x-oss-callback=[CallBack]或者x-oss-callback-var=[CallBackVar]作为一个head带入请求发送。在计算签名CanonicalizedOSSHeaders时,将x-oss-callback-var和x-oss-callback计算在内。如下示例:PUT /test.txt HTTP/1.1 Host: callback-test.oss-test.aliyun-inc.com Accept-ncoding: identity Content-Length: 5 x-oss-callback-var: eyJ4Om15X3ZhciI6ImZvci1jYWxsYmFjay10ZXN0In0= User-Agent: aliyun-sdk-python/0.4.0 (Linux/2.6.32-220.23.2.ali1089.el5.x86_64/x86_64;2.5.4) x-oss-callback: eyJjYWxsYmFja1VybCI6IjEyMS40My4xMTMuODoyMzQ1Ni9pbmRleC5odG1sIiwgICJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mZXRhZz0ke2V0YWd9JnNpemU9JHtzaXplfSZtaW1lVHlwZT0ke21pbWVUeXBlfSZpbWFnZUluZm8uaGVpZ2h0PSR7aW1hZ2VJbmZvLmhlaWdodH0maW1hZ2VJbmZvLndpZHRoPSR7aW1hZ2VJbmZvLndpZHRofSZpbWFnZUluZm8uZm9ybWF0PSR7aW1hZ2VJbmZvLmZvcm1hdH0mbXlfdmFyPSR7eDpteV92YXJ9In0= Host: callback-test.oss-test.aliyun-inc.com Expect: 100-Continue Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: text/plain Authorization: OSS mlepou3zr4u7b14:5a74vhd4UXpmyuudV14Kaen5cY4= Test 如果需要在POST上传Object的时候附带回调参数会稍微复杂一点,callback参数要使用独立的表单域来附加,如下面的示例:--9431149156168 Content-Disposition: form-data; name="callback" eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkmdGFibGU9JHt4OnRhYmxlfSIsImNhbGxiYWNrQm9keVR5cGUiOiJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQifQ==如果拥有自定义参数的话,不能直接将callback-var参数直接附加到表单域中,每个自定义的参数都需要使用独立的表单域来附加,举个例子,如果用户的自定义参数的json为{ "x:var1":"value1", "x:var2":"value2" }那么POST请求的表单域应该如下:--9431149156168 Content-Disposition: form-data; name="callback" eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkmdGFibGU9JHt4OnRhYmxlfSIsImNhbGxiYWNrQm9keVR5cGUiOiJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQifQ== --9431149156168 Content-Disposition: form-data; name="x:var1" value1 --9431149156168 Content-Disposition: form-data; name="x:var2" value2同时可以在policy中添加callback条件(如果不添加callback,则不对该参数做上传验证)如:{ "expiration": "2014-12-01T12:00:00.000Z", "conditions": [ {"bucket": "johnsmith" }, {"callback": "eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkiLCJjYWxsYmFja0JvZHlUeXBlIjoiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIn0="}, ["starts-with", "$key", "user/eric/"], ] } 发起回调请求 如果文件上传成功,OSS会根据用户的请求中的callback参数和自定义参数(callback-var参数),将特定内容以POST方式发送给应用服务器。 POST /index.html HTTP/1.0 Host: 121.43.113.8 Connection: close Content-Length: 181 Content-Type: application/x-www-form-urlencoded User-Agent: ehttp-client/0.0.1 bucket=callback-test&object=test.txt&etag=D8E8FCA2DC0F896FD7CB4CB0031BA249&size=5&mimeType=text%2Fplain&imageInfo.height=&imageInfo.width=&imageInfo.format=&x:var1=for-callback-test 返回回调结果 比如应用服务器端返回的回应请求为: HTTP/1.0 200 OK Server: BaseHTTP/0.3 Python/2.7.6 Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: application/json Content-Length: 9 {"a":"b"} 返回上传结果 再给客户端的内容为: HTTP/1.1 200 OK Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: application/json Content-Length: 9 Connection: keep-alive ETag: "D8E8FCA2DC0F896FD7CB4CB0031BA249" Server: AliyunOSS x-oss-bucket-version: 1442231779 x-oss-request-id: 55F6BF87207FB30F2640C548 {"a":"b"} 需要注意的是,如果类似CompleteMultipartUpload这样的请求,在返回请求本身body中存在内容(如XMl格式的信息),使用上传回调功能后会覆盖原有的body的内容如{"a":"b"},希望对此处做好判断处理。 回调签名 用户设置callback参数后,OSS将按照用户设置的callbackUrl发送POST回调请求给用户的应用服务器。应用服务器收到回调请求之后,如果希望验证回调请求确实是由OSS发起的话,那么可以通过在回调中带上签名来验证OSS的身份。 生成签名 签名在OSS端发生,采用RSA非对称方式签名,私钥加密的过程为:authorization = base64_encode(rsa_sign(private_key, url_decode(path) + query_string + ‘\n’ + body, md5)) 说明 其中private_key为私钥,只有oss知晓,path为回调请求的资源路径,query_string为查询字符串,body为回调的消息体,所以签名过程由以下几步组成: 获取待签名字符串:资源路径经过url解码后,加上原始的查询字符串,加上一个回车符,加上回调消息体 RSA签名:使用秘钥对待签名字符串进行签名,签名的hash函数为md5 将签名后的结果做base64编码,得到最终的签名,签名放在回调请求的authorization头中 如下例:POST /index.php?id=1&index=2 HTTP/1.0 Host: 121.43.113.8 Connection: close Content-Length: 18 authorization: kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA== Content-Type: application/x-www-form-urlencoded User-Agent: ehttp-client/0.0.1 x-oss-pub-key-url: aHR0cDovL2dvc3NwdWJsaWMuYWxpY2RuLmNvbS9jYWxsYmFja19wdWJfa2V5X3YxLnBlbQ== bucket=yonghu-testpath为/index.php,query_string为?id=1&index=2,body为bucket=yonghu-test,最终签名结果为kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA== 验证签名 验证签名的过程即为签名的逆过程,由应用服务器验证,过程如下:Result = rsa_verify(public_key, md5(url_decode(path) + query_string + ‘\n’ + body), base64_decode(authorization))字段的含义与签名过程中描述相同,其中public_key为公钥, authorization为回调头中的签名,整个验证签名的过程分为以下几步: 回调请求的x-oss-pub-key-url头保存的是公钥的url地址的base64编码,因此需要对其做base64解码后获取到公钥,即public_key = urlopen(base64_decode(x-oss-pub-key-url头的值))这里需要注意,用户需要校验x-oss-pub-key-url头的值必须以http://gosspublic.alicdn.com/或者https://gosspublic.alicdn.com/开头,目的是为了保证这个publickey是由OSS颁发的。 获取base64解码后的签名signature = base64_decode(authorization头的值) 获取待签名字符串,方法与签名一致sign_str = url_decode(path) + query_string + ‘\n’ + body 验证签名result = rsa_verify(public_key, md5(sign_str), signature) 以上例为例: 获取到公钥的url地址,即aHR0cDovL2dvc3NwdWJsaWMuYWxpY2RuLmNvbS9jYWxsYmFja19wdWJfa2V5X3YxLnBlbQ==经过base64解码后得到http://gosspublic.alicdn.com/callback_pub_key_v1.pem 签名头kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA==做base64解码(由于为非打印字符,无法显示出解码后的结果) 获取待签名字符串,即url_decode(“index.php”) + “?id=1&index=2” + “\n” + “bucket=yonghu-test”,并做md5 验证签名 应用服务器示例 以下为一段python示例,演示了一个简单的应用服务器,主要是说明验证签名的方法,此示例需要安装M2Crypto库import httplib import base64 import md5 import urllib2 from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer from M2Crypto import RSA from M2Crypto import BIO def get_local_ip(): try: csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) csock.connect(('8.8.8.8', 80)) (addr, port) = csock.getsockname() csock.close() return addr except socket.error: return "" class MyHTTPRequestHandler(BaseHTTPRequestHandler): ''' def log_message(self, format, *args): return ''' def do_POST(self): #get public key pub_key_url = '' try: pub_key_url_base64 = self.headers['x-oss-pub-key-url'] pub_key_url = pub_key_url_base64.decode('base64') if not pub_key_url.startswith("http://gosspublic.alicdn.com/") and not pub_key_url.startswith("https://gosspublic.alicdn.com/"): self.send_response(400) self.end_headers() return url_reader = urllib2.urlopen(pub_key_url) #you can cache it pub_key = url_reader.read() except: print 'pub_key_url : ' + pub_key_url print 'Get pub key failed!' self.send_response(400) self.end_headers() return #get authorization authorization_base64 = self.headers['authorization'] authorization = authorization_base64.decode('base64') #get callback body content_length = self.headers['content-length'] callback_body = self.rfile.read(int(content_length)) #compose authorization string auth_str = '' pos = self.path.find('?') if -1 == pos: auth_str = urllib2.unquote(self.path) + '\n' + callback_body else: auth_str = urllib2.unquote(self.path[0:pos]) + self.path[pos:] + '\n' + callback_body print auth_str #verify authorization auth_md5 = md5.new(auth_str).digest() bio = BIO.MemoryBuffer(pub_key) rsa_pub = RSA.load_pub_key_bio(bio) try: result = rsa_pub.verify(auth_md5, authorization, 'md5') except: result = False if not result: print 'Authorization verify failed!' print 'Public key : %s' % (pub_key) print 'Auth string : %s' % (auth_str) self.send_response(400) self.end_headers() return #do something accoding to callback_body #response to OSS resp_body = '{"Status":"OK"}' self.send_response(200) self.send_header('Content-Type', 'application/json') self.send_header('Content-Length', str(len(resp_body))) self.end_headers() self.wfile.write(resp_body) class MyHTTPServer(HTTPServer): def __init__(self, host, port): HTTPServer.__init__(self, (host, port), MyHTTPRequestHandler) if '__main__' == __name__: server_ip = get_local_ip() server_port = 23451 server = MyHTTPServer(server_ip, server_port) server.serve_forever()其它语言实现的应用服务器如下: Java版本: 下载地址:点击这里 运行方法:解压包运行java -jar oss-callback-server-demo.jar 9000(9000就运行的端口,可以自己指定) PHP版本: 下载地址:点击这里 运行方法:部署到Apache环境下,因为PHP本身语言的特点,取一些数据头部会依赖于环境。所以可以参考例子根据所在环境修改。 Python版本: 下载地址:点击这里 运行方法:解压包直接运行python callback_app_server.py,运行该程序需要安装rsa的依赖。 C#版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Go版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Go版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Ruby版本: 下载地址:点击这里 运行方法: ruby aliyun_oss_callback_server.rb 特别须知 如果传入的callback或者callback-var不合法,则会返回400错误,错误码为”InvalidArgument”,不合法的情况包括以下几类: PutObject()和CompleteMultipartUpload()接口中url和header同时传入callback(x-oss-callback)或者callback-var(x-oss-callback-var)参数 callback或者callback-var(PostObject()由于没有callback-var参数,因此没有此限制,下同)参数过长(超过5KB) callback或者callback-var没有经过base64编码 callback或者callback-var经过base64解码后不是合法的json格式 callback参数解析后callbackUrl字段包含的url超过限制(5个),或者url中传入的port不合法,比如{"callbackUrl":"10.101.166.30:test", "callbackBody":"test"} callback参数解析后callbackBody字段为空 callback参数解析后callbackBodyType字段的值不是”application/x-www-form-urlencoded”或者”application/json” callback参数解析后callbackBody字段中变量的格式不合法,合法的格式为${var} callback-var参数解析后不是预期的json格式,预期的格式应该为{"x:var1":"value1","x:var2":"value2"...} 如果回调失败,则返回203,错误码为”CallbackFailed”,回调失败只是表示OSS没有收到预期的回调响应,不代表应用服务器没有收到回调请求(比如应用服务器返回的内容不是json格式),另外,此时文件已经成功上传到了OSS 应用服务器返回OSS的响应必须带有Content-Length的Header,Body大小不要超过1MB。 Callback支持的地域 Callback目前支持的地域如下:华北 2(北京)、华东 1(杭州)、华北 1(青岛)、华东 2(上海)、上海金融云、华南 1(深圳)、香港、华北 5(呼和浩特)、华北 3(张家口)、中东东部 1(迪拜)、亚太东北 1(日本)、欧洲中部 1(法兰克福)、亚太东南 1(新加坡)、美国东部 1(弗吉尼亚)、美国西部 1(硅谷)、亚太东南 2 (悉尼)以及亚太东南 3(吉隆坡)。

2019-12-01 23:13:51 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 用户只需要在发送给OSS的请求中携带相应的Callback参数,即能实现回调。 现在支持CallBack的API 接口有:PutObject、PostObject、CompleteMultipartUpload。 构造CallBack参数 CallBack参数是由一段经过base64编码的Json字串,用户关键需要指定请求回调的服务器URL(callbackUrl)以及回调的内容(callbackBody)。详细的Json字段如下: 字段 含义 选项 callbackUrl 文件上传成功后OSS向此url发送回调请求,请求方法为POST,body为callbackBody指定的内容。正常情况下,该url需要响应“HTTP/1.1 200 OK”,body必须为JSON格式,响应头Content-Length必须为合法的值,且不超过3MB。 支持同时配置最多5个url,以”;”分割。OSS会依次发送请求直到第一个返回成功为止。 如果没有配置或者值为空则认为没有配置callback。 支持HTTPS地址。 为了保证正确处理中文等情况,callbackUrl需做url编码处理,比如http://example.com/中文.php?key=value&中文名称=中文值 需要编码成 http://example.com/%E4%B8%AD%E6%96%87.php?key=value&%E4%B8%AD%E6%96%87%E5%90%8D%E7%A7%B0=%E4%B8%AD%E6%96%87%E5%80%BC 必选项 callbackHost 发起回调请求时Host头的值,只有在设置了callbackUrl时才有效。 如果没有配置 callbckHost,则会解析callbackUrl中的url并将解析出的host填充到callbackHost中 可选项 callbackBody 发起回调时请求body的值,例如:key=$(key)&etag=$(etag)&my_var=$(x:my_var)。 支持OSS系统变量、自定义变量和常量,支持的系统变量如下表所示 。自定义变量的支持方式在PutObject和CompleteMultipart中是通过callback-var来传递,在PostObject中则是将各个变量通过表单域来传递。 必选项 callbackBodyType 发起回调请求的Content-Type,支持application/x-www-form-urlencoded和application/json,默认为前者。 如果为application/x-www-form-urlencoded,则callbackBody中的变量将会被经过url编码的值替换掉,如果为application/json,则会按照json格式替换其中的变量。 可选项 示例json串如下 { "callbackUrl":"121.101.166.30/test.php", "callbackHost":"oss-cn-hangzhou.aliyuncs.com", "callbackBody":"{\"mimeType\":${mimeType},\"size\":${size}}", "callbackBodyType":"application/json" } { "callbackUrl":"121.43.113.8:23456/index.html", "callbackBody":"bucket=${bucket}&object=${object}&etag=${etag}&size=${size}&mimeType=${mimeType}&imageInfo.height=${imageInfo.height}&imageInfo.width=${imageInfo.width}&imageInfo.format=${imageInfo.format}&my_var=${x:my_var}" } 其中callbackBody中可以设置的系统变量有,其中imageInfo针对于图片格式,如果为非图片格式都为空: 系统变量 含义 bucket bucket object object etag 文件的etag,即返回给用户的etag字段 size object大小,CompleteMultipartUpload时为整个object的大小 mimeType 资源类型,如jpeg图片的资源类型为image/jpeg imageInfo.height 图片高度 imageInfo.width 图片宽度 imageInfo.format 图片格式,如jpg、png等 自定义参数 用户可以通过callback-var参数来配置自定义参数。 自定义参数是一个Key-Value的Map,用户可以配置自己需要的参数到这个Map。在OSS发起POST回调请求的时候,会将这些参数和上一节所述的系统参数一起放在POST请求的body中以方便接收回调方获取。 构造自定义参数的方法和callback参数的方法是一样的,也是以json格式来传递。该json字符串就是一个包含所有自定义参数的Key-Value的Map。 说明 用户自定义参数的Key一定要以x:开头,且必须为小写。否则OSS会返回错误。 假定用户需要设定两个自定义的参数分别为x:var1和x:var2,对应的值分别为value1和value2,那么构造出来的json格式如下: { "x:var1":"value1", "x:var2":"value2" } 构造回调请求 构造完成上述的callback和callback-var两个参数之后,一共有三种方式传给OSS。其中callback为必填参数,callback-var为可选参数,如果没有自定义参数的话可以不用添加callback-var字段。这三种方式如下: 在URL中携带参数。 在Header中携带参数。 在POST请求的body中使用表单域来携带参数。 说明 在使用POST请求上传Object的时候只能使用这种方式来指定回调参数。 这三种方式只能同时使用其中一种,否则OSS会返回InvalidArgument错误。 要将参数附加到OSS的请求中,首先要将上文构造的json字符串使用base64编码,然后按照如下的方法附加到OSS的请求中: 如果在URL中携带参数。把callback=[CallBack]或者callback-var=[CallBackVar]作为一个url参数带入请求发送。计算签名CanonicalizedResource时 ,将callback或者callback-var当做一个sub-resource计算在内 如果在Header中携带参数。把x-oss-callback=[CallBack]或者x-oss-callback-var=[CallBackVar]作为一个head带入请求发送。在计算签名CanonicalizedOSSHeaders时,将x-oss-callback-var和x-oss-callback计算在内。如下示例:PUT /test.txt HTTP/1.1 Host: callback-test.oss-test.aliyun-inc.com Accept-ncoding: identity Content-Length: 5 x-oss-callback-var: eyJ4Om15X3ZhciI6ImZvci1jYWxsYmFjay10ZXN0In0= User-Agent: aliyun-sdk-python/0.4.0 (Linux/2.6.32-220.23.2.ali1089.el5.x86_64/x86_64;2.5.4) x-oss-callback: eyJjYWxsYmFja1VybCI6IjEyMS40My4xMTMuODoyMzQ1Ni9pbmRleC5odG1sIiwgICJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mZXRhZz0ke2V0YWd9JnNpemU9JHtzaXplfSZtaW1lVHlwZT0ke21pbWVUeXBlfSZpbWFnZUluZm8uaGVpZ2h0PSR7aW1hZ2VJbmZvLmhlaWdodH0maW1hZ2VJbmZvLndpZHRoPSR7aW1hZ2VJbmZvLndpZHRofSZpbWFnZUluZm8uZm9ybWF0PSR7aW1hZ2VJbmZvLmZvcm1hdH0mbXlfdmFyPSR7eDpteV92YXJ9In0= Host: callback-test.oss-test.aliyun-inc.com Expect: 100-Continue Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: text/plain Authorization: OSS mlepou3zr4u7b14:5a74vhd4UXpmyuudV14Kaen5cY4= Test 如果需要在POST上传Object的时候附带回调参数会稍微复杂一点,callback参数要使用独立的表单域来附加,如下面的示例:--9431149156168 Content-Disposition: form-data; name="callback" eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkmdGFibGU9JHt4OnRhYmxlfSIsImNhbGxiYWNrQm9keVR5cGUiOiJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQifQ==如果拥有自定义参数的话,不能直接将callback-var参数直接附加到表单域中,每个自定义的参数都需要使用独立的表单域来附加,举个例子,如果用户的自定义参数的json为{ "x:var1":"value1", "x:var2":"value2" }那么POST请求的表单域应该如下:--9431149156168 Content-Disposition: form-data; name="callback" eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkmdGFibGU9JHt4OnRhYmxlfSIsImNhbGxiYWNrQm9keVR5cGUiOiJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQifQ== --9431149156168 Content-Disposition: form-data; name="x:var1" value1 --9431149156168 Content-Disposition: form-data; name="x:var2" value2同时可以在policy中添加callback条件(如果不添加callback,则不对该参数做上传验证)如:{ "expiration": "2014-12-01T12:00:00.000Z", "conditions": [ {"bucket": "johnsmith" }, {"callback": "eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkiLCJjYWxsYmFja0JvZHlUeXBlIjoiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIn0="}, ["starts-with", "$key", "user/eric/"], ] } 发起回调请求 如果文件上传成功,OSS会根据用户的请求中的callback参数和自定义参数(callback-var参数),将特定内容以POST方式发送给应用服务器。 POST /index.html HTTP/1.0 Host: 121.43.113.8 Connection: close Content-Length: 181 Content-Type: application/x-www-form-urlencoded User-Agent: ehttp-client/0.0.1 bucket=callback-test&object=test.txt&etag=D8E8FCA2DC0F896FD7CB4CB0031BA249&size=5&mimeType=text%2Fplain&imageInfo.height=&imageInfo.width=&imageInfo.format=&x:var1=for-callback-test 返回回调结果 比如应用服务器端返回的回应请求为: HTTP/1.0 200 OK Server: BaseHTTP/0.3 Python/2.7.6 Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: application/json Content-Length: 9 {"a":"b"} 返回上传结果 再给客户端的内容为: HTTP/1.1 200 OK Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: application/json Content-Length: 9 Connection: keep-alive ETag: "D8E8FCA2DC0F896FD7CB4CB0031BA249" Server: AliyunOSS x-oss-bucket-version: 1442231779 x-oss-request-id: 55F6BF87207FB30F2640C548 {"a":"b"} 需要注意的是,如果类似CompleteMultipartUpload这样的请求,在返回请求本身body中存在内容(如XMl格式的信息),使用上传回调功能后会覆盖原有的body的内容如{"a":"b"},希望对此处做好判断处理。 回调签名 用户设置callback参数后,OSS将按照用户设置的callbackUrl发送POST回调请求给用户的应用服务器。应用服务器收到回调请求之后,如果希望验证回调请求确实是由OSS发起的话,那么可以通过在回调中带上签名来验证OSS的身份。 生成签名 签名在OSS端发生,采用RSA非对称方式签名,私钥加密的过程为:authorization = base64_encode(rsa_sign(private_key, url_decode(path) + query_string + ‘\n’ + body, md5)) 说明 其中private_key为私钥,只有oss知晓,path为回调请求的资源路径,query_string为查询字符串,body为回调的消息体,所以签名过程由以下几步组成: 获取待签名字符串:资源路径经过url解码后,加上原始的查询字符串,加上一个回车符,加上回调消息体 RSA签名:使用秘钥对待签名字符串进行签名,签名的hash函数为md5 将签名后的结果做base64编码,得到最终的签名,签名放在回调请求的authorization头中 如下例:POST /index.php?id=1&index=2 HTTP/1.0 Host: 121.43.113.8 Connection: close Content-Length: 18 authorization: kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA== Content-Type: application/x-www-form-urlencoded User-Agent: ehttp-client/0.0.1 x-oss-pub-key-url: aHR0cDovL2dvc3NwdWJsaWMuYWxpY2RuLmNvbS9jYWxsYmFja19wdWJfa2V5X3YxLnBlbQ== bucket=yonghu-testpath为/index.php,query_string为?id=1&index=2,body为bucket=yonghu-test,最终签名结果为kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA== 验证签名 验证签名的过程即为签名的逆过程,由应用服务器验证,过程如下:Result = rsa_verify(public_key, md5(url_decode(path) + query_string + ‘\n’ + body), base64_decode(authorization))字段的含义与签名过程中描述相同,其中public_key为公钥, authorization为回调头中的签名,整个验证签名的过程分为以下几步: 回调请求的x-oss-pub-key-url头保存的是公钥的url地址的base64编码,因此需要对其做base64解码后获取到公钥,即public_key = urlopen(base64_decode(x-oss-pub-key-url头的值))这里需要注意,用户需要校验x-oss-pub-key-url头的值必须以http://gosspublic.alicdn.com/或者https://gosspublic.alicdn.com/开头,目的是为了保证这个publickey是由OSS颁发的。 获取base64解码后的签名signature = base64_decode(authorization头的值) 获取待签名字符串,方法与签名一致sign_str = url_decode(path) + query_string + ‘\n’ + body 验证签名result = rsa_verify(public_key, md5(sign_str), signature) 以上例为例: 获取到公钥的url地址,即aHR0cDovL2dvc3NwdWJsaWMuYWxpY2RuLmNvbS9jYWxsYmFja19wdWJfa2V5X3YxLnBlbQ==经过base64解码后得到http://gosspublic.alicdn.com/callback_pub_key_v1.pem 签名头kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA==做base64解码(由于为非打印字符,无法显示出解码后的结果) 获取待签名字符串,即url_decode(“index.php”) + “?id=1&index=2” + “\n” + “bucket=yonghu-test”,并做md5 验证签名 应用服务器示例 以下为一段python示例,演示了一个简单的应用服务器,主要是说明验证签名的方法,此示例需要安装M2Crypto库import httplib import base64 import md5 import urllib2 from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer from M2Crypto import RSA from M2Crypto import BIO def get_local_ip(): try: csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) csock.connect(('8.8.8.8', 80)) (addr, port) = csock.getsockname() csock.close() return addr except socket.error: return "" class MyHTTPRequestHandler(BaseHTTPRequestHandler): ''' def log_message(self, format, *args): return ''' def do_POST(self): #get public key pub_key_url = '' try: pub_key_url_base64 = self.headers['x-oss-pub-key-url'] pub_key_url = pub_key_url_base64.decode('base64') if not pub_key_url.startswith("http://gosspublic.alicdn.com/") and not pub_key_url.startswith("https://gosspublic.alicdn.com/"): self.send_response(400) self.end_headers() return url_reader = urllib2.urlopen(pub_key_url) #you can cache it pub_key = url_reader.read() except: print 'pub_key_url : ' + pub_key_url print 'Get pub key failed!' self.send_response(400) self.end_headers() return #get authorization authorization_base64 = self.headers['authorization'] authorization = authorization_base64.decode('base64') #get callback body content_length = self.headers['content-length'] callback_body = self.rfile.read(int(content_length)) #compose authorization string auth_str = '' pos = self.path.find('?') if -1 == pos: auth_str = urllib2.unquote(self.path) + '\n' + callback_body else: auth_str = urllib2.unquote(self.path[0:pos]) + self.path[pos:] + '\n' + callback_body print auth_str #verify authorization auth_md5 = md5.new(auth_str).digest() bio = BIO.MemoryBuffer(pub_key) rsa_pub = RSA.load_pub_key_bio(bio) try: result = rsa_pub.verify(auth_md5, authorization, 'md5') except: result = False if not result: print 'Authorization verify failed!' print 'Public key : %s' % (pub_key) print 'Auth string : %s' % (auth_str) self.send_response(400) self.end_headers() return #do something accoding to callback_body #response to OSS resp_body = '{"Status":"OK"}' self.send_response(200) self.send_header('Content-Type', 'application/json') self.send_header('Content-Length', str(len(resp_body))) self.end_headers() self.wfile.write(resp_body) class MyHTTPServer(HTTPServer): def __init__(self, host, port): HTTPServer.__init__(self, (host, port), MyHTTPRequestHandler) if '__main__' == __name__: server_ip = get_local_ip() server_port = 23451 server = MyHTTPServer(server_ip, server_port) server.serve_forever()其它语言实现的应用服务器如下: Java版本: 下载地址:点击这里 运行方法:解压包运行java -jar oss-callback-server-demo.jar 9000(9000就运行的端口,可以自己指定) PHP版本: 下载地址:点击这里 运行方法:部署到Apache环境下,因为PHP本身语言的特点,取一些数据头部会依赖于环境。所以可以参考例子根据所在环境修改。 Python版本: 下载地址:点击这里 运行方法:解压包直接运行python callback_app_server.py,运行该程序需要安装rsa的依赖。 C#版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Go版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Go版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Ruby版本: 下载地址:点击这里 运行方法: ruby aliyun_oss_callback_server.rb 特别须知 如果传入的callback或者callback-var不合法,则会返回400错误,错误码为”InvalidArgument”,不合法的情况包括以下几类: PutObject()和CompleteMultipartUpload()接口中url和header同时传入callback(x-oss-callback)或者callback-var(x-oss-callback-var)参数 callback或者callback-var(PostObject()由于没有callback-var参数,因此没有此限制,下同)参数过长(超过5KB) callback或者callback-var没有经过base64编码 callback或者callback-var经过base64解码后不是合法的json格式 callback参数解析后callbackUrl字段包含的url超过限制(5个),或者url中传入的port不合法,比如{"callbackUrl":"10.101.166.30:test", "callbackBody":"test"} callback参数解析后callbackBody字段为空 callback参数解析后callbackBodyType字段的值不是”application/x-www-form-urlencoded”或者”application/json” callback参数解析后callbackBody字段中变量的格式不合法,合法的格式为${var} callback-var参数解析后不是预期的json格式,预期的格式应该为{"x:var1":"value1","x:var2":"value2"...} 如果回调失败,则返回203,错误码为”CallbackFailed”,回调失败只是表示OSS没有收到预期的回调响应,不代表应用服务器没有收到回调请求(比如应用服务器返回的内容不是json格式),另外,此时文件已经成功上传到了OSS 应用服务器返回OSS的响应必须带有Content-Length的Header,Body大小不要超过1MB。 Callback支持的地域 Callback目前支持的地域如下:华北 2(北京)、华东 1(杭州)、华北 1(青岛)、华东 2(上海)、上海金融云、华南 1(深圳)、香港、华北 5(呼和浩特)、华北 3(张家口)、中东东部 1(迪拜)、亚太东北 1(日本)、欧洲中部 1(法兰克福)、亚太东南 1(新加坡)、美国东部 1(弗吉尼亚)、美国西部 1(硅谷)、亚太东南 2 (悉尼)以及亚太东南 3(吉隆坡)。

2019-12-01 23:13:51 0 浏览量 回答数 0
阿里云大学 云服务器ECS com域名 网站域名whois查询 开发者平台 小程序定制 小程序开发 国内短信套餐包 开发者技术与产品 云数据库 图像识别 开发者问答 阿里云建站 阿里云备案 云市场 万网 阿里云帮助文档 免费套餐 开发者工具 云栖号物联网 小程序开发制作 视频内容分析 企业网站制作 视频集锦 代理记账服务 2020阿里巴巴研发效能峰会 企业建站模板 云效成长地图 高端建站 云栖号弹性计算 阿里云云栖号 云栖号案例 云栖号直播