博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
OSS signature 计算
阅读量:6290 次
发布时间:2019-06-22

本文共 4797 字,大约阅读时间需要 15 分钟。

背景

出现 signature 一般出现客户端自签名调 API 的操作中, signature 的计算稍微复杂点,建议最好用 SDK 来替代计算的过程和多样性。如果业务强需求,先要读懂如果计算 signature。

签名分类

Header 头中携带签名。

URL 中携带签名。

签名区别

Header URL
不支持设置 expires 支持设置 expires
常用 method GET、POST、PUT 常用 method GET、PUT
date 时间是 GMT 格式 date 替换成 expires 变成时间戳
signature 不需要 URL encode signature 需要 URL encode

计算签名 demo

当客户通过 header 或者 URL 中自签名计算 signature 时,经常会遇到计算签名失败 “The request signature we calculated does not match the signature you provided” ,可以参考以下 demo 演示了如何调用 API 自签名时上传 Object 到 OSS,注意签名和 header 加入的内容。

#! /us/bin/envy python#Author: hanli#Update: 2018-09-29from optparse import OptionParserimport urllib, urllib2import datetimeimport base64import hmacimport shaimport osimport sysimport timeclass Main():    # Initial input parse  def __init__(self,options):    self.ak = options.ak    self.sk = options.sk    self.ed = options.ed    self.bk = options.bk    self.fi = options.fi    self.oj = options.objects    self.left = '\033[1;31;40m'    self.right = '\033[0m'    self.types = "application/x-www-form-urlencoded"        self.url = 'http://{0}.{1}/{2}'.format(self.bk,self.ed,self.oj)  # Check client input parse  def CheckParse(self):    if (self.ak and self.sk and self.ed and self.bk and self.oj and self.fi) != None:      if str(self.ak and self.sk and self.ed and self.bk and self.oj and self.fi):        self.PutObject()    else:      self.ConsoleLog("error","Input parameters cannot be empty")  # GET local GMT time  def GetGMT(self):      SRM = datetime.datetime.utcnow()    GMT = SRM.strftime('%a, %d %b %Y %H:%M:%S GMT')        return GMT  # GET Signature  def GetSignature(self):    mac = hmac.new("{0}".format(self.sk),"PUT\n\n{0}\n{1}\n/{2}/{3}".format(self.types,self.GetGMT(),self.bk,self.oj), sha)    Signature = base64.b64encode(mac.digest())       return Signature  # PutObject  def PutObject(self):       try:       with open(self.fi) as fd:        files = fd.read()    except Exception as e:      self.ConsoleLog("error",e)      try:      request = urllib2.Request(self.url, files)      request.add_header('Host','{0}.{1}'.format(self.bk,self.ed))      request.add_header('Date','{0}'.format(self.GetGMT()))      request.add_header('Authorization','OSS {0}:{1}'.format(self.ak,self.GetSignature()))      request.get_method = lambda:'PUT'      response = urllib2.urlopen(request,timeout=10)      fd.close()      self.ConsoleLog(response.code,response.headers)    except Exception,e:      self.ConsoleLog("error",e)   # output error log  def ConsoleLog(self,level=None,mess=None):    if level == "error":      sys.exit('{0}[ERROR:]{1}{2}'.format(self.left,self.right,mess))    else:      sys.exit('\nHTTP/1.1 {0} OK\n{1}'.format(level,mess))if __name__ == "__main__":  parser = OptionParser()  parser.add_option("-i",dest="ak",help="Must fill in Accesskey")  parser.add_option("-k",dest="sk",help="Must fill in AccessKeySecrety")  parser.add_option("-e",dest="ed",help="Must fill in endpoint")  parser.add_option("-b",dest="bk",help="Must fill in bucket")  parser.add_option("-o",dest="objects",help="File name uploaded to oss")  parser.add_option("-f",dest="fi",help="Must fill localfile path")  (options, args) = parser.parse_args()  handler = Main(options)  handler.CheckParse()

请求头:

PUT /yuntest HTTP/1.1Accept-Encoding: identityContent-Length: 147Connection: closeUser-Agent: Python-urllib/2.7Date: Sat, 22 Sep 2018 04:36:52 GMTHost: yourBucket.oss-cn-shanghai.aliyuncs.comContent-Type: application/x-www-form-urlencodedAuthorization: OSS B0g3mdt:lNCA4L0P43Ax

响应头:

HTTP/1.1 200 OKServer: AliyunOSSDate: Sat, 22 Sep 2018 04:36:52 GMTContent-Length: 0Connection: closex-oss-request-id: 5BA5C6E4059A3C2FETag: "D0CAA153941AAA1CBDA38AF"x-oss-hash-crc64ecma: 8478734191999037841Content-MD5: 0MqhU5QbIp3Ujqqhy9o4rw==x-oss-server-time: 15

注意

  • Signature 中所有加入计算的参数都要放在 header 中,保持 header 和 Signature 一致。
  • PUT 上传时,Signature 计算的 Content-Type 必须是 application/x-www-form-urlencoded 。
  • 通过header 方式进行签名认证时无法设置过期时间。目前只有 SDK 、URL 签名支持设置过期时间。

使用问题

案例:通过微信小程序请求 OSS 返回签名失败,通过浏览器正常

分析:

  • 只要通过浏览器访问,鉴权通过就证明 OSS 的签名校验是正常的没有问题,可以先排除掉 OSS 端。
  • 客户端一定要在微信小程序上部署 HTTP 抓包,对后续分析很重要,抓包中可以看到所有的请求头和请求参数。
  • 通过浏览器访问时的 HTTP 抓包。

5

  • 通过 403 和 200 的抓包反复对比发现,通过小程序发出的 HTTP 请求和浏览器发起的 HTTP 请求的 URL 、signature、expires 都一样,唯一的区别就是微信小程序携带了 Content-type ,而通过 Chrom 的请求是没有携带 Content-type,怀疑矛头指向了这里。
  • 经过代码确认,发现 signature 计算时是没有包含 Content-tpye 头的,而小程序发起的请求携带的 Content-tpye ,OSS 收到后会按照携带了 Content-tpye 去计算 signature ,所以每次计算都不一样。

遇到类似问题,抓包是最能快速看到问题的。同时也必须要了解下 OSS 请求 header 中携带了 Content-tpye ,那么 signature 计算就要加上 Content-tpye ,保持一致。

案例:通过多个语言版本 OSS SDK 测试,在使用 CDN 结合 OSS 用法时,客户端使用 CDN 域名计算 signature,发起 HEAD 请求,OSS 收到后返回 403 ;

1

分析:

出现这个问题不区分什么 SDK 都会出现,问题原因是由于客户端发起的 HEAD 请求在通过 CDN 回原到 OSS 时,CDN 回原是用的 GET 请求,而 OSS 收到时就用 GET 请求方式去计算签名,得到的结果肯定和客户端计算不一致,可以升级到阿里云 CDN 处理。以上分析只适合上述场景。

问题可以通过 tcpdump 抓包或者 Wireshark 对比一下即可知道。

转载地址:http://eecta.baihongyu.com/

你可能感兴趣的文章
迷人的卡耐基说话术
查看>>
PHP导出table为xls出现乱码解决方法
查看>>
PHP问题 —— 丢失SESSION
查看>>
Java中Object类的equals()和hashCode()方法深入解析
查看>>
数据库
查看>>
dojo.mixin(混合进)、dojo.extend、dojo.declare
查看>>
Python 数据类型
查看>>
iOS--环信集成并修改头像和昵称(需要自己的服务器)
查看>>
PHP版微信权限验证配置,音频文件下载,FFmpeg转码,上传OSS和删除转存服务器本地文件...
查看>>
教程前言 - 回归宣言
查看>>
PHP 7.1是否支持操作符重载?
查看>>
Vue.js 中v-for和v-if一起使用,来判断select中的option为选中项
查看>>
Java中AES加密解密以及签名校验
查看>>
定义内部类 继承 AsyncTask 来实现异步网络请求
查看>>
VC中怎么读取.txt文件
查看>>
如何清理mac系统垃圾
查看>>
企业中最佳虚拟机软件应用程序—Parallels Deskto
查看>>
Nginx配置文件详细说明
查看>>
怎么用Navicat Premium图标编辑器创建表
查看>>
Spring配置文件(2)配置方式
查看>>