使用Elixir和HTTPoison访问Azure存储服务REST API

使用Elixir和HTTPoison访问Azure存储服务REST API,rest,azure,elixir,azure-storage,httpoison,Rest,Azure,Elixir,Azure Storage,Httpoison,我正试图使用长生不老药进入,但我很难让它工作。如果我使用包(的包装器),我就能够连接,但当我尝试构建请求并使用时,我就无法连接 最近的错误消息 身份验证失败 服务器无法对请求进行身份验证。确保包含签名的授权标头的值格式正确。\n请求ID:00000000-0000-0000-0000-000000000000\n时间:2017-08-02T21:46:08.6488342Z 我注意到了几个问题: 您在请求中包含了Date请求头,但它不包含在您的字符串\u to \u sign中。将此头

我正试图使用长生不老药进入,但我很难让它工作。如果我使用包(的包装器),我就能够连接,但当我尝试构建请求并使用时,我就无法连接

最近的错误消息

身份验证失败
服务器无法对请求进行身份验证。确保包含签名的授权标头的值格式正确。\n请求ID:00000000-0000-0000-0000-000000000000\n时间:2017-08-02T21:46:08.6488342Z


    • 我注意到了几个问题:

    • 您在请求中包含了
      Date
      请求头,但它不包含在您的
      字符串\u to \u sign
      中。将此头包含在您的
      字符串中以进行签名
      ,或者从请求头中删除此头
    • 您在
      规范化的\u资源中包含了
      超时:30
      ,但它未包含在您的请求URL中。同样,在请求查询字符串中添加
      timeout=30
      ,或者从
      规范化的\u资源中删除
      timeout:30
    • 我没有这样使用Elixir,所以我不知道请求头是如何工作的,但您将请求头命名为
      x-ms-date-h
      x-ms-version-h
      。它们不应该分别是
      x-ms-date
      x-ms-version

    • 谢谢你的反馈#1我从标题中删除了日期#2我从
      caonicialized\u资源中删除了
      timeout:30
      #3我删除了
      -h
      ;那是个打字错误。它仍然不工作,但服务器使用以下字符串对错误消息的
      部分进行签名,看起来效果更好。我已经更新了问题,以反映您的建议,并显示最新的错误消息。我已使其正常工作。我在
      规范化资源
      中有另一个输入错误。我必须删除一个空格,
      /{storage\u name}/{container\u name}
      ->
      /{storage\u name}/{container\u name}
      。我遵循微软文档中的示例
      GET\n\n\n\n\n\n\n\n\n\n微软日期:2009年10月11日21:49:13格林尼治标准时间\nx微软版本:2009-09-19\n/myaccount/mycontainer\ncomp:metadata\nrestype:container\ntimeout:20
      ;空格似乎是一个打字错误
      。\n/myaccount/mycontainer\n…
      。问题中的代码现在应该可以工作了。谢谢你的帮助!您也可以尝试以下方法:
      # mix.exs
      defp deps do
        {:httpoison, "~> 0.12"}
        {:timex, "~> 3.1"}
      end
      
      # account credentials
      storage_name            = "storage_name"
      container_name          = "container_name"
      storage_key             = "storage_key"
      storage_service_version = "2017-04-17" # fixed version
      
      request_date =
        Timex.now
        |> Timex.format!("{RFC1123}") # Wed, 02 Aug 2017 00:52:10 +0000
        |> String.replace("+0000", "GMT") # Wed, 02 Aug 2017 00:52:10 GMT
      
      # set canonicalized headers
      x_ms_date    = "x-ms-date:#{request_date}"
      x_ms_version = "x-ms-version:#{storage_service_version}"
      
      # assign values for string_to_sign
      verb                   = "GET\n"
      content_encoding       = "\n"
      content_language       = "\n"
      content_length         = "\n"
      content_md5            = "\n"
      content_type           = "\n"
      date                   = "\n"
      if_modified_since      = "\n"
      if_match               = "\n"
      if_none_match          = "\n"
      if_unmodified_since    = "\n"
      range                  = "\n"
      canonicalized_headers  = "#{x_ms_date}\n#{x_ms_version}\n"
      canonicalized_resource = "/#{storage_name}/#{container_name}\ncomp:list\nrestype:container" # removed timeout. removed space
      
      # concat string_to_sign
      string_to_sign =
        verb                  <>
        content_encoding      <>
        content_language      <>
        content_length        <>
        content_md5           <>
        content_type          <>
        date                  <>
        if_modified_since     <>
        if_match              <>
        if_none_match         <>
        if_unmodified_since   <>
        range                 <>
        canonicalized_headers <>
        canonicalized_resource
      
      # decode storage_key
      {:ok, decoded_key} =
        storage_key
        |> Base.decode64
      
      # sign and encode string_to_sign
      signature =
        :crypto.hmac(:sha256, decoded_key, string_to_sign)
        |> Base.encode64
      
      # build authorization header
      authorization_header = "SharedKey #{storage_name}:#{signature}"
      
      # build request and use HTTPoison
      url     = "https://storage_name.blob.core.windows.net/container_name?restype=container&comp=list"
      headers = [ # "Date": request_date,
                 "x-ms-date": request_date, # fixed typo
                 "x-ms-version": storage_service_version, # fixed typo
                 # "Accept": "application/json",
                 "Authorization": authorization_header]
      options = [ssl: [{:versions, [:'tlsv1.2']}], recv_timeout: 500]
      
      HTTPoison.get(url, headers, options)