Java Azure请求签名



我正在使用最新的Azure SDK存储模拟器。我正在尝试将请求签名到我的blob。当我运行下面的代码时,我得到了auth错误。

虽然我已经检查了好几次代码是否符合Azure SDK blob访问规范,但我不知道出了什么问题。

这是控制台输出:

GET

x-ms-date:Sun, 23 Sep 2012 04:04:07 GMT
/devstoreaccount1/tweet/?comp=list
SharedKey devstoreaccount1:Hx3Pm9knGwCb4Hs9ftBX/+QlX0kCGGlUOX5g6JHZ9Kw=
Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.

这是代码:

public static void signRequest(HttpURLConnection request, String account, String key) throws Exception
{
SimpleDateFormat fmt = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss");
fmt.setTimeZone(TimeZone.getTimeZone("GMT"));
String date = fmt.format(Calendar.getInstance().getTime()) + " GMT";
StringBuilder sb = new StringBuilder();
sb.append("GETn"); // method
sb.append('n'); // md5 (optional)
sb.append('n'); // content type
sb.append('n'); // legacy date
sb.append("x-ms-date:" + date + 'n'); // headers
sb.append(request.getURL().getPath() + "/tweet/?comp=list"); // resource TODO: "?comp=..." if present
System.out.println(sb.toString());
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(Base64.decode(key), "HmacSHA256"));
String authKey = new String(Base64.encode(mac.doFinal(sb.toString().getBytes("UTF-8"))));
String auth = "SharedKey " + account + ":" + authKey;
request.setRequestProperty("x-ms-date", date);
request.setRequestProperty("Authorization", auth);
request.setRequestMethod("GET");
System.out.println(auth);
}

public static void main(String args[]) throws Exception
{
String account = "devstoreaccount1";
String key = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
HttpURLConnection connection = (HttpURLConnection) (new URL("http://localhost:10000/devstoreaccount1")).openConnection();
signRequest(connection, account, key);
connection.connect();
System.out.println(connection.getResponseMessage());
}

在收到Gaurav和Smarx的反馈后,这是代码,我仍然收到同样的错误。你能给我看一些代码吗?否则很难理解。

public static void sign(HttpURLConnection request, String account, String key, String url) throws Exception
{
SimpleDateFormat fmt = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss");
fmt.setTimeZone(TimeZone.getTimeZone("GMT"));
String date = fmt.format(Calendar.getInstance().getTime()) + " GMT";
StringBuilder sb = new StringBuilder();
sb.append("GETn"); // method
sb.append('n'); // md5 (optional)
sb.append('n'); // content type
sb.append('n'); // legacy date
sb.append("x-ms-date:" + date + 'n'); // headers
sb.append("x-ms-version:2009-09-19n"); // headers
sb.append("/devstoreaccount1/devstoreaccount1/n$maxresults:1ncomp:listnrestype:container"); // resource TODO: "?comp=..." if present
System.out.println(sb.toString());
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(Base64.decode(key), "HmacSHA256"));
String authKey = new String(Base64.encode(mac.doFinal(sb.toString().getBytes("UTF-8"))));
String auth = "SharedKeyLite " + account + ":" + authKey;
request.setRequestProperty("x-ms-date", date);
request.setRequestProperty("Authorization", auth);
request.setRequestMethod("GET");
System.out.println(auth);
}
public static void main(String args[]) throws Exception
{
String account = "devstoreaccount1";
String key = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
String url = "http://127.0.0.1:10000/devstoreaccount1/?restype=container&comp=list&$maxresults=1";
HttpURLConnection connection = (HttpURLConnection) (new URL(url)).openConnection();
sign(connection, account, key, url);
connection.connect();
System.out.println(connection.getResponseMessage());
}

EDITGaurav的答案在哪里?:-)我相信他已经回答并提到,您似乎正在构建SharedKeyLite签名,因此应该在您的授权标头中使用"SharedKeyLite"。


我认为Gaurav的回答是对的,但我注意到了其他三个问题:

  1. 您似乎在调用http://localhost/devstoreaccount1,但您正在计算http://localhost/devstoreaccount1/tweet/?comp=list的签名。请确保URL匹配
  2. 对于存储模拟器,我认为您的规范化资源实际上应该是/devstoreaccount1/devstoreaccount1/tweet/?comp=list。(注意帐户名称的重复。)通常应该是/<account>/<path>,对于存储模拟器,帐户名称显示在路径中
  3. x-ms-version标头在哪里?我相信这是必须的

UPDATE以下是一些使用两种方法的工作代码,一种使用Shared Key,另一种使用共享密钥精简版。希望这能澄清问题。请注意,要使用存储模拟器,您需要将URL切换回localhost:10000/devstoreaccount1。签名代码应该仍然适用于模拟器,但我还没有测试它。Base64库来自这里:http://commons.apache.org/codec/apidocs/org/apache/commons/codec/binary/Base64.html.

import java.net.*;
import java.util.*;
import java.text.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import org.apache.commons.codec.binary.Base64;
public class Test
{
private static Base64 base64 = new Base64();
public static void signRequestSK(HttpURLConnection request, String account, String key) throws Exception
{
SimpleDateFormat fmt = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss");
fmt.setTimeZone(TimeZone.getTimeZone("GMT"));
String date = fmt.format(Calendar.getInstance().getTime()) + " GMT";
StringBuilder sb = new StringBuilder();
sb.append("GETn"); // method
sb.append('n'); // content encoding
sb.append('n'); // content language
sb.append('n'); // content length
sb.append('n'); // md5 (optional)
sb.append('n'); // content type
sb.append('n'); // legacy date
sb.append('n'); // if-modified-since
sb.append('n'); // if-match
sb.append('n'); // if-none-match
sb.append('n'); // if-unmodified-since
sb.append('n'); // range
sb.append("x-ms-date:" + date + 'n'); // headers
sb.append("x-ms-version:2009-09-19n");
sb.append("/" + account + request.getURL().getPath() + "ncomp:list");
//System.out.println(sb.toString());
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(base64.decode(key), "HmacSHA256"));
String authKey = new String(base64.encode(mac.doFinal(sb.toString().getBytes("UTF-8"))));
String auth = "SharedKey " + account + ":" + authKey;
request.setRequestProperty("x-ms-date", date);
request.setRequestProperty("x-ms-version", "2009-09-19");
request.setRequestProperty("Authorization", auth);
request.setRequestMethod("GET");
System.out.println(auth);
}
public static void signRequestSKL(HttpURLConnection request, String account, String key) throws Exception
{
SimpleDateFormat fmt = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss");
fmt.setTimeZone(TimeZone.getTimeZone("GMT"));
String date = fmt.format(Calendar.getInstance().getTime()) + " GMT";
StringBuilder sb = new StringBuilder();
sb.append("GETn"); // method
sb.append('n'); // md5 (optional)
sb.append('n'); // content type
sb.append('n'); // legacy date
sb.append("x-ms-date:" + date + 'n'); // headers
sb.append("x-ms-version:2009-09-19n");
sb.append("/" + account + request.getURL().getPath() + "?comp=list");
//System.out.println(sb.toString());
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(base64.decode(key), "HmacSHA256"));
String authKey = new String(base64.encode(mac.doFinal(sb.toString().getBytes("UTF-8"))));
String auth = "SharedKeyLite " + account + ":" + authKey;
request.setRequestProperty("x-ms-date", date);
request.setRequestProperty("x-ms-version", "2009-09-19");
request.setRequestProperty("Authorization", auth);
request.setRequestMethod("GET");
System.out.println(auth);
}

public static void main(String args[]) throws Exception
{
String account = args[0];
String key = args[1];
HttpURLConnection connection = (HttpURLConnection) (new URL("http://" + account + ".blob.core.windows.net/?comp=list")).openConnection();
signRequestSKL(connection, account, key);
connection.connect();
System.out.println(connection.getResponseMessage());
connection = (HttpURLConnection) (new URL("http://" + account + ".blob.core.windows.net/?comp=list")).openConnection();
signRequestSK(connection, account, key);
connection.connect();
System.out.println(connection.getResponseMessage());
}
}

基于此处的文档:http://msdn.microsoft.com/en-us/library/windowsazure/dd179428,我认为您构建签名的"规范化资源字符串"部分的方式存在问题。

我注意到的几件事:

  • 您正在将查询字符串参数(comp=list)附加到此字符串这是你不应该做的
  • 如果您针对开发存储构建此字符串(您正在做的),"devstoreaccount1"应该出现两次

例如,如果我试图在我的开发存储帐户中只列出一个blob容器,这应该是基于以下请求URL的规范化资源字符串-127.0.0.1:10000/defstoreaccount1/?restype=容器&comp=列表&最大结果=1:

/devstoreaccount1/devstoreaccount1/

$maxresults:1

comp:列出

重新类型:容器

最新更新