使用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)