[英]Error connecting to azure blob storage API from R
我試圖通過R中的REST API使用Azure存儲。我正在使用覆蓋Curl的包httr
。
您可以使用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")
試圖列出blob:
content(GET(url,config = headerstuff, verbose() ))
在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>"
-> 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
<-
谷歌搜索這個問題似乎沒有產生一致的原因,但這可能是由於我的格式/請求結構不好。 為此我檢查了:
headerstuff
添加了
encoding="Base64"
,進一步
headerstuff
了
MSDN論壇問題,但返回了相同的錯誤消息
sak
))作為加密密鑰)UTF8轉換的signaturestring
字符串的版本作為要在SharedKey授權中使用的值。 有什么明顯的錯誤嗎? 還有其他事情要檢查嗎? 代碼是否適用於其他人?
看起來你的問題是關鍵。 您提供的密鑰字符串實際上是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() ))
雖然沒有列出blob,但這種方式不再存在身份驗證錯誤。 也許這是一個不同的問題。
此外,我更改了創建日期/時間的方式,以更“安全”地將當地時間更改為GMT。
您似乎直接在Authorization標頭中使用了您帳戶的密鑰。 要對請求進行身份驗證,您必須使用發出請求的帳戶的密鑰對請求進行簽名,並將該簽名作為請求的一部分傳遞。 有關如何構建Authorization標頭的詳細信息,請參閱Azure存儲服務的身份驗證 。
另請注意,該服務在錯誤響應中返回StringToSign。 那么,你的代碼應該做的是將以下公式應用於StringToSign =“GET \\ n \\ n \\ n \\ n \\ n \\ n \\ n \\ n \\ n \\ n \\ n \\ n \\ n-nx-ms-date:Wed, 2015年3月25日22:24:12 GMT \\ nx-ms-version:2014-02-14 \\ n / preconstuff / pings \\ ncomp:list \\ nrestype:container“(不含引號):
Signature=Base64(HMAC-SHA256(AccountKey, UTF8(StringToSign)))
服務如何計算StringToSign將在上面共享的鏈接中詳細說明。
通過MrFlick上面的示例代碼工作並使其工作我不得不改變一些事情。
日期字符串必須在英語區域設置中設置,例如:
lct <- Sys.getlocale("LC_TIME")
Sys.setlocale("LC_TIME", "us")
requestdate <- format(Sys.time(),"%a, %d %b %Y %H:%M:%S %Z", tz="GMT")
Sys.setlocale("LC_TIME", lct)
應使用參數之間的\\ n格式化'signaturestring':
signaturestring <- paste0("GET", paste(rep("\n", 12), collapse=""),
"x-ms-date:", requestdate,
"\nx-ms-version:2009-09-19\n/preconstuff/pings\ncomp:list\nrestype:container")
編輯:以下程序適合我。 基於Steph Locke的例子。
library(httr)
library(RCurl)
azureBlobCall <- function(url, verb, key, requestBody=NULL, headers=NULL, ifMatch="", md5="") {
urlcomponents <- httr::parse_url(url)
account <- gsub(".blob.core.windows.net", "", urlcomponents$hostname, fixed = TRUE)
container <- urlcomponents$path
# get timestamp in us locale
lct <- Sys.getlocale("LC_TIME"); Sys.setlocale("LC_TIME", "us")
`x-ms-date` <- format(Sys.time(),"%a, %d %b %Y %H:%M:%S %Z", tz="GMT")
Sys.setlocale("LC_TIME", lct)
# if requestBody exist get content length in bytes and content type
`Content-Length` <- ""; `Content-Type` <- ""
if(!is.null(requestBody)) {
if(class(requestBody) == "form_file") {
`Content-Length` <- (file.info(requestBody$path))$size
`Content-Type` <- requestBody$type
} else {
requestBody <- enc2utf8(as.character(requestBody))
`Content-Length` <- nchar(requestBody, "bytes")
`Content-Type` <- "text/plain; charset=UTF-8"
}
}
# combine timestamp and version headers with any input headers, order and create the CanonicalizedHeaders
headers <- setNames(c(`x-ms-date`, "2015-04-05", unlist(headers)),
c("x-ms-date", "x-ms-version", unclass(names(unlist(headers)))))
headers <- headers[order(names(headers))]
CanonicalizedHeaders <- paste(names(headers), headers, sep=":", collapse = "\n")
# create CanonicalizedResource headers and add any queries to it
if(!is.null(urlcomponents$query)) {
components <- setNames(unlist(urlcomponents$query), unclass(names(unlist(urlcomponents$query))))
componentstring <- paste0("\n", paste(names(components[order(names(components))]),
components[order(names(components))], sep=":", collapse = "\n"))
} else componentstring <- ""
CanonicalizedResource <- paste0("/",account,"/",container, componentstring)
# create the authorizationtoken
signaturestring <- paste0(verb, "\n\n\n", `Content-Length`, "\n", md5, "\n", `Content-Type`, "\n\n\n",
ifMatch, "\n\n\n\n", CanonicalizedHeaders, "\n", CanonicalizedResource)
requestspecificencodedkey <- RCurl::base64(
digest::hmac(key=RCurl::base64Decode(key, mode="raw"),
object=enc2utf8(signaturestring),
algo= "sha256", raw=TRUE)
)
authorizationtoken <- paste0("SharedKey ", account, ":", requestspecificencodedkey)
# make the call
headers_final <- add_headers(Authorization=authorizationtoken, headers, `Content-Type` = `Content-Type`)
call <- httr::VERB(verb=verb, url=url, config=headers_final, body=requestBody, verbose())
print("signaturestring");print(signaturestring);
print(headers_final); print(call)
return(content(call))
}
## Tests. Replace 'key' and 'accountName' with yours
key <- "YowThr***********RDw=="
# Creates a container named 'test'
azureBlobCall("https://accountName.blob.core.windows.net/test?restype=container", "PUT", key)
# Creates a blob named 'blob' under container 'test' with the content of "Hej världen!"
azureBlobCall("https://accountName.blob.core.windows.net/test/blob", "PUT", key,
headers = c("x-ms-blob-type"="BlockBlob"), requestBody = "Hej världen!") #upload_file("blob.txt"))
# List all blob in the container 'test'
azureBlobCall("https://accountName.blob.core.windows.net/test?comp=list&restype=container", "GET", key)
# deletes the blobl named 'blob'
azureBlobCall("https://accountName.blob.core.windows.net/test/blob", "DELETE", key)
# Creates a blob named 'blob' under container 'test' with and upload the file 'blob.txt'
azureBlobCall("https://accountName.blob.core.windows.net/test/blob", "PUT", key,
headers = c("x-ms-blob-type"="BlockBlob"), requestBody = upload_file("blob.txt"))
# deletes the container named 'test'
azureBlobCall("https://accountName.blob.core.windows.net/test?restype=container", "DELETE", key)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.