问题描述
我正在尝试使用 REST API 调用 Azure 存储队列,但出现错误
在 HTTP 请求中找到的 MAC 签名 'UCiypkoySXueF4scXt+EqQESf5VXmAVLJUA93+3W10M=' 与任何不一样 计算签名。服务器使用以下字符串进行签名:'POST 文本/纯文本
我的 C# 代码是
var Client = new HttpClient();
var RequestDateString = DateTime.UtcNow.ToString("R",CultureInfo.InvariantCulture);
if (Client.DefaultRequestHeaders.Contains("x-ms-date"))
Client.DefaultRequestHeaders.Remove("x-ms-date");
Client.DefaultRequestHeaders.Add("x-ms-date",RequestDateString);
var StorageAccountName = "storaxxxxxxxsnd";
var StorageKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==";
String urlPath = String.Format("{0}/messages","splitator");
Uri uri = new Uri(string.Format("https://{0}.queue.core.windows.net/",StorageAccountName) + urlPath);
if (Client.DefaultRequestHeaders.Contains("Authorization"))
Client.DefaultRequestHeaders.Remove("Authorization");
var canonicalizedStringToBuild = string.Format("{0}\n{1}",RequestDateString,$"/{StorageAccountName}/{uri.AbsolutePath.Trimstart('/')}");
string signature;
using (var hmac = new HMACSHA256(Convert.FromBase64String(StorageKey)))
{
byte[] dataToHmac = Encoding.UTF8.GetBytes(canonicalizedStringToBuild);
signature = Convert.ToBase64String(hmac.ComputeHash(dataToHmac));
}
string authorizationHeader = string.Format($"{StorageAccountName}:" + signature);
Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("SharedKey",authorizationHeader);
Client.DefaultRequestHeaders.Accept.Clear();
Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain"));
if (Client.DefaultRequestHeaders.Contains("x-ms-version"))
Client.DefaultRequestHeaders.Remove("x-ms-version");
Client.DefaultRequestHeaders.Add("x-ms-version","2015-12-11");
// if (httpMethod == HttpMethod.Delete || httpMethod == HttpMethod.Put)
// {
// if (Client.DefaultRequestHeaders.Contains("If-Match"))
// Client.DefaultRequestHeaders.Remove("If-Match");
// Currently I'm not using optimistic concurrency :-(
try
{
//Client.DefaultRequestHeaders.Add("If-Match","*");
var stringContent = new StringContent("TESTAUTH",Encoding.UTF8,"text/plain");
var response= Client.PostAsync(uri,stringContent);
var resu=response.Result;
}
catch(Exception ex)
{
}
我不确定我错过了什么。我尝试了各种组合,但都失败了。
我也尝试过微软推荐的 stringToSign 公式
I tried using canonical headers too
string signature;
var stringTosign = "POST\n" + "\n" + "\n" + "1024" + "\n" + "\n" + "text/plain\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + dateInRfc1123Format + "/xxxxxx/splitator/messages";
var hmac = new HMACSHA256(Convert.FromBase64String(accountKey));
var headerval= accountName + ":" + Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringTosign)));
Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("SharedKey",headerval);
Client.DefaultRequestHeaders.Accept.Clear();
解决方法
我修复了您代码中的问题,现在可以正常工作了。请试一试:
namespace ConsoleApp25
{
class Program
{
static void Main(string[] args)
{
var Client = new HttpClient();
var StorageAccountName = "yy1";
var StorageKey = "xxxx";
var apiversion = "2020-02-10";
var queue_name = "myqueue2";
String urlPath = String.Format("{0}/messages",queue_name);
Uri uri = new Uri(string.Format("https://{0}.queue.core.windows.net/{1}",StorageAccountName,urlPath));
//define a message to send
string raw_message = "TESTAUTH is ok";
//to send the message to the queue storage,the raw message must be formatted as below
string queue_message = $"<QueueMessage><MessageText>{raw_message}</MessageText></QueueMessage>";
//define the content type
string content_type = "text/plain; charset=utf-8";
//define date
var RequestDateString = DateTime.UtcNow.ToString("R",CultureInfo.InvariantCulture);
string StringToSign = String.Format("POST\n"
+ "\n" // content encoding
+ "\n" // content language
+ queue_message.Length + "\n" // content length
+ "\n" // content md5
+ content_type +"\n" // content type
+ "\n" // date
+ "\n" // if modified since
+ "\n" // if match
+ "\n" // if none match
+ "\n" // if unmodified since
+ "\n" // range
+ "x-ms-date:" + RequestDateString + "\nx-ms-version:" + apiversion + "\n" // headers
+ "/{0}/{1}/{2}",queue_name,"messages"); //url
string auth = SignThis(StringToSign,StorageKey,StorageAccountName);
//define authorization header
if (Client.DefaultRequestHeaders.Contains("Authorization"))
Client.DefaultRequestHeaders.Remove("Authorization");
Client.DefaultRequestHeaders.Add("Authorization",auth);
Client.DefaultRequestHeaders.Accept.Clear();
//define x-ms-version header
Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain"));
if (Client.DefaultRequestHeaders.Contains("x-ms-version"))
Client.DefaultRequestHeaders.Remove("x-ms-version");
Client.DefaultRequestHeaders.Add("x-ms-version",apiversion);
//define the x-ms-date header
if (Client.DefaultRequestHeaders.Contains("x-ms-date"))
Client.DefaultRequestHeaders.Remove("x-ms-date");
Client.DefaultRequestHeaders.Add("x-ms-date",RequestDateString);
try
{
var stringContent = new StringContent(queue_message,Encoding.UTF8,"text/plain");
var response = Client.PostAsync(uri,stringContent);
var resu = response.Result;
}
catch (Exception ex)
{
}
Console.WriteLine("**completed**");
Console.ReadLine();
}
private static String SignThis(String StringToSign,string Key,string Account)
{
String signature = string.Empty;
byte[] unicodeKey = Convert.FromBase64String(Key);
using (HMACSHA256 hmacSha256 = new HMACSHA256(unicodeKey))
{
Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(StringToSign);
signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
}
String authorizationHeader = String.Format(
CultureInfo.InvariantCulture,"{0} {1}:{2}","SharedKey",Account,signature);
return authorizationHeader;
}
}
}
如果您不想生成shared key
,因为它并不容易,您可以在rest api中使用sas token
进行身份验证。