Azure Blob存储:使用共享密钥身份验证的快照blob

时间:2017-05-18 09:47:53

标签: azure azure-storage-blobs

我正在使用下面提到的来自MS的快照休息api

https://myaccount.blob.core.windows.net/mycontainer/myblob?comp=snapshot

https://docs.microsoft.com/en-us/rest/api/storageservices/snapshot-blob

授权我生成的共享密钥适用于所有其他具有GET REST API调用的操作,例如GetBlob,ListContainer,ListBlob。

我认为对于POST调用我收到错误但是生成授权共享密钥的逻辑是相同的。

Cannonical Resource /storageaccountname/containername/8447a36f-43a3-4927-a23f-b8839f4c55e3DataDisk.vhd 排版:快照

Cannonical Headers:x-ms-date:星期四,2017年5月18日09:42:05 GMT X-MS-版本:2014年2月14日

得到以下提到的错误:

Map<String, String> requestHeaders = new HashMap<>(); requestHeaders.put("x-ms-version", "2014-02-14"); requestHeaders.put("x-ms-date", getStorageDate()); getAuthorizationHeader("PUT","storageaccount","storagekey",new URI("https://storageaccount.blob.core.windows.net/vhds/8447a36f-43a3-4927-a23f-b8839f4c55e3.vhd?comp=snapshot"),requestHeaders); } public static String getStorageDate() { Date d = new Date(System.currentTimeMillis()); SimpleDateFormat f = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz"); f.setTimeZone(TimeZone.getTimeZone("GMT")); String dateString = f.format(d); return dateString; } public static String getAuthorizationHeader(String verb, String storageAccount, String storageKey, URI resourceURI, Map<String, String> requestHeaders) throws Exception { String authorizationStringToHash = getAuthorizationStringToHash(verb, storageAccount, requestHeaders, resourceURI); String authorizationHash = hashString(storageKey, authorizationStringToHash); System.out.println("StorageAccoutName::" + storageAccount); System.out.println("Storage Key::" + storageKey); System.out.println("authorizationStringToHash::" + authorizationStringToHash); System.out.println("authorizationHash:: " + authorizationHash); /* System.out.println(HttpClientFactory.getInstance() .createHeader("Authorization", "SharedKey " + storageAccount + ":" + authorizationHash).getValue());*/ System.out.println("Authorization SharedKey " + storageAccount + ":" + authorizationHash); return ""; } public static String getAuthorizationStringToHash(String verb, String storageAccount, Map<String, String> headers, URI resourceURI) throws Exception { Map<String, String> headersToCanonicalize = new HashMap<String, String>(); String contentEncoding = ""; String contentLanguage = ""; String contentLength = ""; String contentMD5 = ""; String contentType = ""; String date = ""; String ifModifiedSince = ""; String ifMatch = ""; String ifNoneMatch = ""; String ifUnModifiedSince = ""; String range = ""; Set<String> keySet = headers.keySet(); for (String header : keySet) { if ("content-encoding".equals(header)) { contentEncoding = headers.get(header); } else if ("content-language".equals(header)) { contentLanguage = headers.get(header); } else if ("content-length".equals(header)) { contentLength = headers.get(header); } else if ("content-md5".equals(header)) { contentType = headers.get(header); } else if ("content-type".equals(header)) { contentType = headers.get(header); } else if ("date".equals(header)) { date = ""; } else if ("if-modified-since".equals(header)) { ifModifiedSince =headers.get(header); } else if ("if-match".equals(header)) { ifMatch = headers.get(header); } else if ("if-none-match".equals(header)) { ifNoneMatch =headers.get(header); } else if ("if-unmodified-since".equals(header)) { ifUnModifiedSince =headers.get(header); } else if ("range".equals(header)) { range = headers.get(header); } else { headersToCanonicalize.put(header, headers.get(header)); } } StringBuffer hashBuffer = new StringBuffer(verb); hashBuffer.append("\n"); hashBuffer.append(contentEncoding); hashBuffer.append("\n"); hashBuffer.append(contentLanguage); hashBuffer.append("\n"); hashBuffer.append(contentLength); hashBuffer.append("\n"); hashBuffer.append(contentMD5); hashBuffer.append("\n"); hashBuffer.append(contentType); hashBuffer.append("\n"); hashBuffer.append(date); hashBuffer.append("\n"); hashBuffer.append(ifModifiedSince); hashBuffer.append("\n"); hashBuffer.append(ifMatch); hashBuffer.append("\n"); hashBuffer.append(ifNoneMatch); hashBuffer.append("\n"); hashBuffer.append(ifUnModifiedSince); hashBuffer.append("\n"); hashBuffer.append(range); hashBuffer.append("\n"); List<String> headerNames = new ArrayList<String>(headersToCanonicalize.keySet()); Collections.sort(headerNames); for (String headerName : headerNames) { hashBuffer.append(canonicalizeHeader(headerName,headersToCanonicalize.get(headerName))); hashBuffer.append("\n"); } hashBuffer.append(canonicalizeResource(storageAccount, resourceURI.getPath(), resourceURI.getQuery())); return hashBuffer.toString(); } public static String hashString(String key, String stringToHash) throws Exception { byte[] keyBytes = DatatypeConverter.parseBase64Binary(key); SecretKey myKey = new SecretKeySpec(keyBytes, "HMACSHA256"); Mac mac = Mac.getInstance("HMACSHA256"); mac.init(myKey); byte[] stringUTF8Bytes = stringToHash.getBytes("UTF-8"); byte[] macBytes = mac.doFinal(stringUTF8Bytes); return DatatypeConverter.printBase64Binary(macBytes); } public static String canonicalizeHeader(String headerName,String headervalue) { return headerName + ":" + headervalue; } // uri must not start with / public static String canonicalizeResource(String account, String resourcePath, String query) { StringBuffer canonicalResourceBuffer = new StringBuffer("/"); canonicalResourceBuffer.append(account); canonicalResourceBuffer.append(resourcePath); List<String> sortedQueryParams = getOrderedQueryParams(query); for (String queryParam : sortedQueryParams) { canonicalResourceBuffer.append("\n"); canonicalResourceBuffer.append(queryParam); } System.out.println("Cannonical Resource "+canonicalResourceBuffer.toString()); return canonicalResourceBuffer.toString(); } public static List<String> getOrderedQueryParams(String queryParamsString) { Map<String, String> queryParams = new HashMap<String, String>(); if ((queryParamsString == null) || (queryParamsString.isEmpty())) { return Collections.EMPTY_LIST; } String[] queryParamsArray = queryParamsString.split("&"); if ((queryParamsArray == null) || (queryParamsArray.length == 0)) { return Collections.EMPTY_LIST; } Arrays.sort(queryParamsArray); for (String queryParam : queryParamsArray) { queryParam = queryParam.trim(); queryParam = queryParam.replaceFirst("[ \t]*=[ \t]*", "="); String[] parts = queryParam.split("="); if (parts.length == 2) { String key = parts[0]; String value = parts[1]; String currentValue = queryParams.get(key); if (currentValue == null) { queryParams.put(key, value); } else { queryParams.put(key, currentValue + "," + value); } } } List<String> names = new ArrayList(queryParams.keySet()); Collections.sort(names); List<String> sortedCanonicalQueryParams = new ArrayList<String>(); for (String name : names) { sortedCanonicalQueryParams.add(name + ":" + queryParams.get(name)); } return sortedCanonicalQueryParams; } 服务器无法验证请求。确保正确形成Authorization标头的值,包括签名。 RequestId:70447bc6-0001-0043-4271-d05281000000时间:2017-05-19T07:27:25.2321062Z 在HTTP请求'7FfeYCQ4SUfWH5OH1DLG7Qx1ZRceffesdDwmGKQWZYo ='中找到的MAC签名与任何计算签名不同。服务器使用以下字符串进行签名:'PUT 0 x-ms-date:Fri,2017年5月19日07:26:46 GMT x-ms-version:2014-02-14 / cscagilitysouthcentralus / vhds / 8447a36f-43a3-4927-a23f -b8839f4c55e3AgilityDataDisk.vhd comp:snapshot'。  

让我知道在标题中我需要设置任何其他强制参数,如内容长度,内容类型等,

网址:https://storageaccountName.blob.core.windows.net/vhds/8447a36f-43a3-4927-a23f-b8839f4c55e3.vhd?comp=snapshot

标题: 授权:SharedKey storgeaccountname:gHYtJ5uOEQNztcdTpqAr3E20cARyFnrV8b3zuDpO9uk =

x-ms-version:2014-02-14 x-ms-date:2017年5月17日星期三10:01:47 GMT

直接生成Authorization SharedKey的Java代码我们可以创建类并复制粘贴此代码:

public static void main(String ... arg)抛出URISyntaxException,Exception {

{{1}}

2 个答案:

答案 0 :(得分:0)

通常,当您收到此类错误响应时,您应该检查服务器的字符串到符号(包含在错误响应中)并与您自己进行比较,并找出存在差异的原因。< / p>

在这种情况下,您可以看到&#34; comp&#34;查询参数有一个值&#34; snapshot?comp = snapshot /&#34;这是不正确的。请检查您的代码,以确保您没有附加&#34;?comp = snapshot&#34;两次到URL。 (实际发送给服务的那个,而不是用于计算签名的那个。)

答案 1 :(得分:0)

根据Azure存储的错误响应消息,我们需要为POST和Delete操作传递Content-length。

在上面的代码中,设置

之后

requestHeaders.put(&#34; content-length&#34;,&#34; 0&#34;);

它在工作。

AuthenticationFailed服务器无法验证请求。确保正确形成Authorization标头的值,包括签名。 RequestId:70447bc6-0001-0043-4271-d05281000000时间:2017-05-19T07:27:25.2321062Z在HTTP请求中找到的MAC签名&#39; 7FfeYCQ4SUfWH5OH1DLG7Qx1ZRceffesdDwmGKQWZYo =&#39;与任何计算签名不同。服务器使用以下字符串进行签名:&#39; PUT 0 x-ms-date:星期五,2017年5月19日07:26:46 GMT x-ms-version:2014-02-14 / cscagilitysouthcentralus / vhds / 8447a36f-43a3- 4927-a23f-b8839f4c55e3AgilityDataDisk.vhd comp:snapshot&#39;。