问题描述
我使用的是最新的Azure SDK存储模拟器。我试图登录到我的BLOB的请求。当我运行低于code我得到权威性的错误。
我无法弄清楚什么是错的,虽然我已经检查好几次了code符合的Azure SDK BLOB访问规格。
下面是控制台输出:
GETX-MS-日期:孙老师,2012年9月23日4时04分07秒GMT
/ devstoreaccount1 /鸣叫/?补偿=名单
SharedKey devstoreaccount1:Hx3Pm9knGwCb4Hs9ftBX / + QlX0kCGGlUOX5g6JHZ9Kw =
服务器无法验证请求。确保授权头的值是正确形成,包括签名。
下面是code:
公共静态无效signRequest(HttpURLConnection的要求,字符串帐户,字符串键)抛出异常
{
SimpleDateFormat的FMT =新的SimpleDateFormat(EEE,DD MMM YYYY HH:MM:SS);
fmt.setTimeZone(TimeZone.getTimeZone(GMT));
字符串日期= fmt.format(Calendar.getInstance()的getTime())+GMT; StringBuilder的SB =新的StringBuilder();
sb.append(GET \\ n); // 方法
sb.append('\\ n'); // MD5(可选)
sb.append('\\ n'); // 内容类型
sb.append('\\ n'); //遗产日期
sb.append(X-MS-日期:+日期+的'\\ n'); //头
sb.append(request.getURL()的getPath()+/鸣叫/补偿=列表?); // TODO资源:补偿= ...如果present 的System.out.println(sb.toString());
苹果MAC = Mac.getInstance(HmacSHA256);
mac.init(新SecretKeySpec(Base64.de code(键),HmacSHA256));
字符串AUTHKEY =新的String(Base64.en code(mac.doFinal(sb.toString()的getBytes(UTF-8))));
字符串AUTH =SharedKey+账号+:+ AUTHKEY;
request.setRequestProperty(X-MS-日,日期);
request.setRequestProperty(授权,验证);
request.setRequestMethod(GET);
的System.out.println(AUTH);
}公共静态无效的主要(字符串ARGS [])抛出异常
{
串账户=devstoreaccount1;
字符串键=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq / K1SZFPTOtr / KBHBeksoGMGw ==;
。HttpURLConnection的连接=(HttpURLConnection类)(新URL(HTTP://本地主机:10000 / devstoreaccount1))的openConnection();
signRequest(连接,帐户密钥);
connection.connect();
的System.out.println(connection.getResponseMessage());
}
从拉夫和Smarx反馈后,这里是code,我还是得到同样的错误。你能告诉我一些code?这是很难以其他方式理解。
公共静态无效标志(HttpURLConnection的要求,字符串账户,串键,字符串URL)抛出异常
{
SimpleDateFormat的FMT =新的SimpleDateFormat(EEE,DD MMM YYYY HH:MM:SS);
fmt.setTimeZone(TimeZone.getTimeZone(GMT));
字符串日期= fmt.format(Calendar.getInstance()的getTime())+GMT; StringBuilder的SB =新的StringBuilder();
sb.append(GET \\ n); // 方法
sb.append('\\ n'); // MD5(可选)
sb.append('\\ n'); // 内容类型
sb.append('\\ n'); //遗产日期
sb.append(X-MS-日期:+日期+的'\\ n'); //头
sb.append(X-MS-版本:2009-09-19 \\ n); //头
sb.append(/ devstoreaccount1 / devstoreaccount1 / \\ N $的maxResults:1 \\ NCOMP:列表\\ nrestype:集装箱); // TODO资源:补偿= ...如果present 的System.out.println(sb.toString());
苹果MAC = Mac.getInstance(HmacSHA256);
mac.init(新SecretKeySpec(Base64.de code(键),HmacSHA256));
字符串AUTHKEY =新的String(Base64.en code(mac.doFinal(sb.toString()的getBytes(UTF-8))));
字符串AUTH =SharedKeyLite+账号+:+ AUTHKEY;
request.setRequestProperty(X-MS-日,日期);
request.setRequestProperty(授权,验证);
request.setRequestMethod(GET);
的System.out.println(AUTH);
} 公共静态无效的主要(字符串ARGS [])抛出异常
{ 串账户=devstoreaccount1;
字符串键=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq / K1SZFPTOtr / KBHBeksoGMGw ==;
字符串URL =http://127.0.0.1:10000/devstoreaccount1/?restype=container&comp=list&$maxresults=1;
HttpURLConnection的连接=(HttpURLConnection类)(新的URL(网址))的openConnection()。
签字(连接,帐户,钥匙,URL);
connection.connect();
的System.out.println(connection.getResponseMessage());
}
修改在哪里拉夫的回答去? :-)我相信他已经回答了,并提到,你似乎是构建一个共享密钥精简版的签名,因此应在授权头使用SharedKeyLite。
我觉得拉夫是正确的,他的回答,但我注意到另外三个问题:
- 您似乎正在为
HTTP调用://本地主机/ devstoreaccount1
,但你计算为HTTP签名://本地主机/ devstoreaccount1 /鸣叫/?补偿=列表
。确保网址匹配。 - 对于存储模拟器,我想你的规范化的资源实际上应该是
/ devstoreaccount1 / devstoreaccount1 /鸣叫/?补偿=列表
。 (请注意,帐户名称的重复。)它一般应/<帐户> /<路径>
,并为存储模拟器,帐户名显示出来路径。 - 哪里
X-MS-版本
头?我的相信的那是必需的。
更新这里的一些工作code有两种方法,一种使用共享密钥,并使用共享密钥精简版之一。希望这将清除的东西了。注意,要使用存储模拟器,你要切换URL回本地主机:10000 / devstoreaccount1
。签名code还是应该在模拟器上工作,但我没有测试它。该Base64编码库从这里走过:的.
进口java.net *。
进口的java.util。*;
导入的java.text *。
javax.crypto中导入*。
javax.crypto.spec中导入*。
进口org.apache.commons codec.binary.Base64。公共类测试
{
私有静态Base64编码的base64 =新的Base64(); 公共静态无效signRequestSK(HttpURLConnection的要求,字符串帐户,字符串键)抛出异常
{
SimpleDateFormat的FMT =新的SimpleDateFormat(EEE,DD MMM YYYY HH:MM:SS);
fmt.setTimeZone(TimeZone.getTimeZone(GMT));
字符串日期= fmt.format(Calendar.getInstance()的getTime())+GMT; StringBuilder的SB =新的StringBuilder();
sb.append(GET \\ n); // 方法
sb.append('\\ n'); //内容编码
sb.append('\\ n'); //内容语言
sb.append('\\ n'); //内容长度
sb.append('\\ n'); // MD5(可选)
sb.append('\\ n'); // 内容类型
sb.append('\\ n'); //遗产日期
sb.append('\\ n'); //如果 - 修改 - 自
sb.append('\\ n'); //如果匹配
sb.append('\\ n'); //如果 - 无 - 匹配
sb.append('\\ n'); //如果未改性的,因为
sb.append('\\ n'); // 范围
sb.append(X-MS-日期:+日期+的'\\ n'); //头
sb.append(X-MS-版本:2009-09-19 \\ n);
sb.append(/+账户+ request.getURL()的getPath()+\\ NCOMP:表); //System.out.println(sb.toString());
苹果MAC = Mac.getInstance(HmacSHA256);
mac.init(新SecretKeySpec(base64.de code(键),HmacSHA256));
字符串AUTHKEY =新的String(base64.en code(mac.doFinal(sb.toString()的getBytes(UTF-8))));
字符串AUTH =SharedKey+账号+:+ AUTHKEY;
request.setRequestProperty(X-MS-日,日期);
request.setRequestProperty(X-MS-版本,2009-09-19);
request.setRequestProperty(授权,验证);
request.setRequestMethod(GET);
的System.out.println(AUTH);
} 公共静态无效signRequestSKL(HttpURLConnection的要求,字符串帐户,字符串键)抛出异常
{
SimpleDateFormat的FMT =新的SimpleDateFormat(EEE,DD MMM YYYY HH:MM:SS);
fmt.setTimeZone(TimeZone.getTimeZone(GMT));
字符串日期= fmt.format(Calendar.getInstance()的getTime())+GMT; StringBuilder的SB =新的StringBuilder();
sb.append(GET \\ n); // 方法
sb.append('\\ n'); // MD5(可选)
sb.append('\\ n'); // 内容类型
sb.append('\\ n'); //遗产日期
sb.append(X-MS-日期:+日期+的'\\ n'); //头
sb.append(X-MS-版本:2009-09-19 \\ n);
sb.append(/+账户+ request.getURL()的getPath()+=补偿名单?); //System.out.println(sb.toString());
苹果MAC = Mac.getInstance(HmacSHA256);
mac.init(新SecretKeySpec(base64.de code(键),HmacSHA256));
字符串AUTHKEY =新的String(base64.en code(mac.doFinal(sb.toString()的getBytes(UTF-8))));
字符串AUTH =SharedKeyLite+账号+:+ AUTHKEY;
request.setRequestProperty(X-MS-日,日期);
request.setRequestProperty(X-MS-版本,2009-09-19);
request.setRequestProperty(授权,验证);
request.setRequestMethod(GET);
的System.out.println(AUTH);
} 公共静态无效的主要(字符串ARGS [])抛出异常
{
串账户= ARGS [0];
字符串键= ARGS [1];
。HttpURLConnection的连接=(HttpURLConnection类)(新URL(HTTP://+账号+?.blob.core.windows.net /补偿=列表))的openConnection();
signRequestSKL(连接,帐户密钥);
connection.connect();
的System.out.println(connection.getResponseMessage()); 。连接=(HttpURLConnection类)(新URL(HTTP://+账号+?.blob.core.windows.net /补偿=列表))的openConnection();
signRequestSK(连接,帐户密钥);
connection.connect();
的System.out.println(connection.getResponseMessage());
}
}
I am using the latest Azure SDK Storage emulator. I am trying to sign a request to my blob. When I run the below code I am getting auth error.
I can't figure out what is wrong, although I have checked several times that the code conforms to the Azure SDK blob access specs.
Here is the console output:
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.
Here is the code:
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("GET\n"); // 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());
}
After feedback from Gaurav and Smarx, here is the code, I still get the same error. Can you show me some code? It is hard to understand otherwise.
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("GET\n"); // 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-19\n"); // headers
sb.append("/devstoreaccount1/devstoreaccount1/\n$maxresults:1\ncomp:list\nrestype: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());
}
EDIT Where did Gaurav's answer go? :-) I believe he already answered and mentioned that you appear to be constructing a Shared Key Lite signature and should thus use "SharedKeyLite" in your authorization header.
I think Gaurav is right in his answer, but I noticed three other issues:
- You seem to be making a call to
http://localhost/devstoreaccount1
, but you're computing a signature forhttp://localhost/devstoreaccount1/tweet/?comp=list
. Make sure the URLs match up. - For the storage emulator, I think your canonicalized resource should actually be
/devstoreaccount1/devstoreaccount1/tweet/?comp=list
. (Note the repetition of the account name.) It should generally be/<account>/<path>
, and for the storage emulator, the account name shows up in the path. - Where's the
x-ms-version
header? I believe that's required.
UPDATE Here's some working code with two methods, one that uses Shared Key and one that uses Shared Key Lite. Hopefully this clears things up. Note that to use the storage emulator, you'll want to switch the URL back to localhost:10000/devstoreaccount1
. The signature code should still work for the emulator, but I haven't tested it. The Base64 library came from here: 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("GET\n"); // 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-19\n");
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("GET\n"); // 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-19\n");
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());
}
}
这篇关于Java的Azure的请求签名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!