2

我正在尝试使用 Elixir通过他们的 REST API 访问 Azure 存储服务,但我很难让Authentication Header工作。如果我使用ex_azure包(erlazure的包装器),我可以连接,但当我尝试构建请求并使用HTTPoison时不能连接。

最近的错误消息

<?xml version=\"1.0\" encoding=\"utf-8\"?>
<Error>
  <Code>AuthenticationFailed</Code>
  <Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.\nRequestId:00000000-0000-0000-0000-000000000000\nTime:2017-08-02T21:46:08.6488342Z</Message>
  <AuthenticationErrorDetail>The MAC signature found in the HTTP request '<signature>' is not the same as any computed signature. Server used following string to sign: 'GET\n\n\nWed, 02 Aug 2017 21:46:08
    GMT\nx-ms-date-h:Wed, 02 Aug 2017 21:46:08 GMT\nx-ms-version-h:2017-05-10\n/storage_name/container_name?comp=list'.</AuthenticationErrorDetail>
</Error>

第一次编辑后

  <?xml version=\"1.0\" encoding=\"utf-8\"?>
  <Error>
    <Code>AuthenticationFailed</Code>
    <Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.\nRequestId:00000000-0000-0000-0000-000000000000\nTime:2017-08-03T03:03:57.1385277Z</Message>
    <AuthenticationErrorDetail>The MAC signature found in the HTTP request '<signature>' is not the same as any computed signature. Server used following string to sign: 'GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:Thu, 03 Aug
      2017 03:03:57 GMT\nx-ms-version:2017-04-17\n/storage_name/container_name\ncomp:list\nrestype:container'.</AuthenticationErrorDetail>
  </Error>

依赖项

# mix.exs
defp deps do
  {:httpoison, "~> 0.12"}
  {:timex, "~> 3.1"}
end

代码

  • 我是否正在格式化身份验证标头 ( string_to_sign) 对吗?
  • 我使用编码/解码对吗?
  • 我是否将标头正确添加到 HTTPoison?
  • 我应该为 REST 操作使用其他东西而不是 HTTPoison 吗?
# 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)

笔记

我使用/尝试过的一些资源...

4

1 回答 1

1

我注意到的几个问题:

  1. 您在请求中包含Date了请求标头,但它不包含在您的string_to_sign. 在您的请求头中包含此标头string_to_sign或从请求标头中删除此标头。
  2. 您包含timeout:30在您的canonicalized_resource但它不包含在您的请求 URL 中。同样,添加timeout=30您的请求查询字符串或timeout:30canonicalized_resource.
  3. 我没有像这样使用 Elixir,所以我不知道请求标头在那里是如何工作的,但是您将请求标头命名为x-ms-date-hand x-ms-version-h。他们不应该是x-ms-datex-ms-version分别吗?
于 2017-08-03T01:38:34.533 回答