1

我正在尝试使用自定义 ruby​​ 代码(从 azure 的官方 php 库移植)为我的 windows 媒体服务文件创建一个 SAS url。代码如下所示:

def create_signature(path = '/', resource = 'b', permissions = 'r', start = '', expiry = '', identifier = '')
  # If resource is a container, remove the last part (which is the filename)
  path = path.split('/').reverse.drop(1).reverse.join('/') if resource == 'c'
  canonicalizedResource = "/mediasvc78m7lfh2gnn2x/#{path}"

  stringToSign  = []
  stringToSign << permissions
  stringToSign << start
  stringToSign << expiry
  stringToSign << canonicalizedResource
  stringToSign << identifier

  stringToSign = stringToSign.join("\n")
  signature    = OpenSSL::HMAC.digest('sha256', wms_api_key, stringToSign.encode(Encoding::UTF_8))
  signature    = Base64.encode64(signature)

  return signature
end

def createSignedQueryString(path = '/', query_string = '', resource = 'b', permissions = 'r', start = '', expiry = '', identifier = '')
  base = 'https://mediasvc78m7lfh2gnn2x.blob.core.windows.net'
  uri  = Addressable::URI.new

  # Parts
  parts       = {}
  parts[:st]  = URI.unescape(start) unless start == ''
  parts[:se]  = URI.unescape(expiry)
  parts[:sr]  = URI.unescape(resource)
  parts[:sp]  = URI.unescape(permissions)
  parts[:si]  = URI.unescape(identifier) unless identifier == ''
  parts[:sig] = URI.unescape( create_signature(path, resource, permissions, start, expiry) )

  uri.query_values = parts
  return "#{base}/#{path}?#{uri.query}"
end

运行时:

puts createSignedQueryString(
  'asset-12514a3b-565f-4150-9543-e3c2b4531428/video.mp4',
  nil,
  'b', 
  'r', 
  (Time.now - 5*60).utc.iso8601, 
  (Time.now + 30*60).utc.iso8601
)

它给了我以下网址:https ://mediasvc78m7lfh2gnn2x.blob.core.windows.net/asset-12514a3b-565f-4150-9543-e3c2b4531428/video.mp4?se=2014-02-20T12%3A59%3A19Z&sig=RDc9nVMuf1dy %2BPrnzCkA8pZfgry2ZwrF08u9itf4v%2FA%3D%0A&sp=r&sr=b&st=2014-02-20T12%3A24%3A19Z

当我尝试将浏览器指向它时,我得到:

<Error>
<Code>AuthenticationFailed</Code>
<Message>
Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:ee7fd18f-cd1f-4179-8a58-c8b746d0549c Time:2014-02-20T12:29:27.0468171Z
</Message>
<AuthenticationErrorDetail>
Signature did not match. String to sign used was r 2014-02-20T12:24:19Z 2014-02-20T12:59:19Z /mediasvc78m7lfh2gnn2x/asset-12514a3b-565f-4150-9543-e3c2b4531428/video.mp4
</AuthenticationErrorDetail>
</Error>

您知道什么可能导致该错误(或如何调试它?)以及如何处理?提前致谢。

4

1 回答 1

3

假设您直接从门户使用存储密钥并在 wms_api_key变量中使用它(或者换句话说,您wms_api_key是 Base64 编码的字符串,我相信您需要先将其转换为字节数组以计算签名。您需要做类似的事情:

signature    = OpenSSL::HMAC.digest('sha256', Base64.strict_decode64(wms_api_key), stringToSign.encode(Encoding::UTF_8))

这是基于Azure SDK for RubyGithub 上的源代码。

更新

我又发现了一个问题。如果您注意到您的 SAS URL,您会注意到查询字符串参数%0A的末尾sig本质上是一个换行符。不知道为什么会这样,但我认为当您执行以下操作时它会自动插入:

signature    = Base64.encode64(signature)

但是,如果我使用strict_encode64代替encode64方法,则不会插入此方法,并且一切正常。所以试试下面的代码:

signature    = Base64.strict_encode64(signature)

我刚试过,它对我很有用。

于 2014-02-25T02:29:22.963 回答