从R连接到azure blob存储API时出错

Ste*_*cke 6 r azure-storage httr

我试图通过R中的REST API使用Azure存储.我正在使用httr覆盖Curl 的包.

建立

您可以使用R-fiddle:http://www.r-fiddle.org/#/fiddle?id = vh8uqGmM

library(httr)
requestdate<-format(Sys.time(),"%a, %d %b %Y %H:%M:%S GMT")
url<-"https://preconstuff.blob.core.windows.net/pings?restype=container&comp=list"
sak<-"Q8HvUVJLBJK+wkrIEG6LlsfFo19iDjneTwJxX/KXSnUCtTjgyyhYnH/5azeqa1bluGD94EcPcSRyBy2W2A/fHQ=="
signaturestring<-paste0("GET",paste(rep("\n",12),collapse=""),
"x-ms-date:",requestdate,"
x-ms-version:2009-09-19
/preconstuff/pings
comp:list
restype:container")

headerstuff<-add_headers(Authorization=paste0("SharedKey preconstuff:",
                         RCurl::base64(digest::hmac(key=sak,
                         object=enc2utf8(signaturestring),
                         algo= "sha256"))),
                    `x-ms-date`=requestdate,
                    `x-ms-version`= "2009-09-19")
Run Code Online (Sandbox Code Playgroud)

试图列出blob:

content(GET(url,config = headerstuff, verbose() ))
Run Code Online (Sandbox Code Playgroud)

错误

顶级消息

在HTTP请求'Q8HvUVJLBJK + wkrIEG6LlsfFo19iDjneTwJxX /KXSnUCtTjgyyhYnH/5azeqa1bluGD94EcPcSRyBy2W2A/fHQ =='中找到的MAC签名与任何计算签名不同.

回复内容

[1] "<?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:1ab26da5-0001-00dc-6ddb-15e35c000000\nTime:2015-03-26T17:51:42.7190620Z</Message>
<AuthenticationErrorDetail>The MAC signature found in the HTTP request 'NTM1ODZjMjhhZmMyZGM3NDM0YTFjZDgwNGE0ODVmMzVjNDhkNjBkNzk1ZjNkZjJjOTNlNjUxYTMwMjRhNzNlYw==' 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, 26 Mar 2015 17:52:37 GMT\nx-ms-version:2009-09-19\n/preconstuff/pings\ncomp:list\nrestype:container'.
</AuthenticationErrorDetail></Error>"
Run Code Online (Sandbox Code Playgroud)

详细输出

-> GET /pings?restype=container&comp=list HTTP/1.1
-> User-Agent: curl/7.39.0 Rcurl/1.95.4.5 httr/0.6.1
-> Host: preconstuff.blob.core.windows.net
-> Accept-Encoding: gzip
-> Accept: application/json, text/xml, application/xml, */*
-> Authorization: SharedKey preconstuff:OTRhNTgzYmY3OTY3M2UzNjk3ODdjMzk3OWM3ZmU0OTA4MWU5NTE2OGYyZGU3YzRjNjQ1M2NkNzY0ZTcyZDRhYQ==
-> x-ms-date: Thu, 26 Mar 2015 17:56:27 GMT
-> x-ms-version: 2009-09-19
-> 
<- HTTP/1.1 403 Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
<- Content-Length: 719
<- Content-Type: application/xml
<- Server: Microsoft-HTTPAPI/2.0
<- x-ms-request-id: 3d47770c-0001-0085-2313-6d466f000000
<- Date: Thu, 26 Mar 2015 17:56:27 GMT
<- 
Run Code Online (Sandbox Code Playgroud)

解决错误

谷歌搜索这个问题似乎没有产生一致的原因,但这可能是由于我的格式/请求结构不好.为此我检查了:

  1. 我已经验证了我的密钥是正确的(它只是门户网站的c&p)
  2. 我确保日期格式正确
  3. 最近有一个documentDB SO表明它可能是一个时钟偏差问题,我注意到我的x-ms-date比响应中的Date早了一秒.我已经尝试发送一个绝对过去的固定值,但在15分钟的容差范围内.没有得到消息的改变.
  4. 增加了encoding="Base64"headerstuff进一步的MSDN论坛的问题,但返回相同的错误信息
  5. 继@ Serdar的答案之后,我整合了一个签名字符串的构造(我已经验证这与错误消息中提供的字符串相匹配),然后在base64中编码hmac-sha256(使用辅助访问密钥(sak) UTF8的加密密钥版本转换signaturestring为要在SharedKey授权中使用的值.
  6. 继@ Serdar的评论之后,签名字符串和主要请求中使用的日期必须相同,因此定义一次并重复使用

有什么明显的错误吗?还有其他事情要检查吗?代码是否适用于其他人?

MrF*_*ick 4

看来你的问题出在钥匙上。您提供的密钥字符串实际上是 base64 编码的。在使用它来签署请求之前,您需要将其解码为原始向量。例如:

url<-"https://preconstuff.blob.core.windows.net/pings?restype=container&comp=list"
sak<-"Q8HvUVJLBJK+wkrIEG6LlsfFo19iDjneTwJxX/KXSnUCtTjgyyhYnH/5azeqa1bluGD94EcPcSRyBy2W2A/fHQ=="

requestdate<-format(Sys.time(),"%a, %d %b %Y %H:%M:%S %Z", tz="GMT")
signaturestring<-paste0("GET",paste(rep("\n",12),collapse=""),
"x-ms-date:",requestdate,"
x-ms-version:2009-09-19
/preconstuff/pings
comp:list
restype:container")

headerstuff<-add_headers(Authorization=paste0("SharedKey preconstuff:",
                         RCurl::base64(digest::hmac(key=RCurl::base64Decode(sak, mode="raw"),
                         object=enc2utf8(signaturestring),
                         algo= "sha256", raw=TRUE))),
                    `x-ms-date`=requestdate,
                    `x-ms-version`= "2009-09-19")

content(GET(url,config = headerstuff, verbose() ))
Run Code Online (Sandbox Code Playgroud)

尽管没有列出 blob,但这种方式不会再出现身份验证错误。也许这是一个不同的问题。

另外,我更改了创建日期/时间的方式,以更“安全”地将当地时间更改为 GMT。