我正在尝试在 Unity 场景中使用 Azure 存储中的 OBJ 文件,该文件将作为网站应用程序运行。我正在运行蓝铜矿,并创建了一个包含文件的容器。我可以在 Azure 存储资源管理器中的模拟器->Blob 容器->MyContainer 下看到该文件。我创建了运行此 docker compose 脚本的 Azurite:
azurite:
image: mcr.microsoft.com/azure-storage/azurite
container_name: "azurite"
hostname: azurite
restart: always
ports:
- "10000:10000"
- "10001:10001"
- "10002:10002"
在 Azure 存储资源管理器中,我可以看到这是我的连接字符串:
AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;DefaultEndpointsProtocol=http;BlobEndpoint=http://127.0.0.1:10000/dev storeaccount1;QueueEndpoint=http://127.0.0.1:10001/devstoreaccount1;TableEndpoint=http //127.0.0.1:10002/devstoreaccount1;
当我在 Azure 存储资源管理器中复制文件的 URL 时,我可以看到它是:
http://127.0.0.1:10000/devstoreaccount1/MyContainer/MyFile.jpg
在我的 Unity 脚本中,我将这段代码称为:
private string DownloadString(string url)
{
using (WebClient client = new WebClient())
{
client.Headers.Add("Authorization", "SharedKey devstoreaccount1:Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==");
return client.DownloadString(url);
}
}
并这样称呼它
private void myTest(){
string objUrl = "http://127.0.0.1:10000/devstoreaccount1/MyContainer/MyFile.obj";
string objData = DownloadString(objUrl);
}
但我收到此错误:
System.Net.WebException: The remote server returned an error: (403) Server failed to authenticate the request. Make sure the value of the Authorization header is formed correctly including the signature..
System.Net.WebException:远程服务器返回错误:(403)服务器无法验证请求。确保授权标头的值格式正确,包括签名。
当您在授权标头中传递不正确的签名并且还缺少一些标头时,就会出现上述错误。
在
DownloadString
函数中,您在授权标头中传递了一个直接访问密钥,这是不正确的,您还需要添加日期和 x-ms-version。
标题应该是这样的:
x-ms-version: 2014-02-14
x-ms-date: Fri, 26 Jun 2015 23:39:12 GMT
Authorization: SharedKey myaccount:ctzMq410TV3wS7upTBcuxxxxx=
根据此MS-Docs,您只需要在授权标头中传递签名。
要从访问密钥获取签名、日期和版本,您可以使用以下 C# 代码
代码:
using System;
using System.Globalization;
using System.Net;
using System.Security.Cryptography;
class Program
{
static void Main(string[] args)
{
string authorization, date, apiVersion;
Blobs(out authorization, out date, out apiVersion);
Console.WriteLine($"Authorization: {authorization}");
Console.WriteLine($"Date: {date}");
Console.WriteLine($"API Version: {apiVersion}");
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
static void Blobs(out string auth, out string date, out string apiversion)
{
string Account = "devstoreaccount1";
string Key = "<Your-access-key>";
string Container = "<your container name>";
string blob = "MyFile.obj";
apiversion = "2021-06-08";
DateTime dt = DateTime.UtcNow;
string StringToSign = String.Format("GET\n"
+ "\n" // content encoding
+ "\n" // content language
+ "\n" // content length
+ "\n" // content md5
+ "\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:" + dt.ToString("R") + "\nx-ms-version:" + apiversion + "\n" // headers
+ "/{0}/{1}/{2}", Account, Container, blob);
string signature = SignThis(StringToSign, Key, Account);
auth = string.Format(
CultureInfo.InvariantCulture,
"{0} {1}:{2}",
"SharedKey",
Account,
signature);
date = dt.ToString("R");
}
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));
}
return signature;
}
}
输出:
Authorization: SharedKey xxxxx:pjnrtx34Je88XqiAnq67Txxxxxxx
Date: Sat, 21 Oct 2023 05:18:57 GMT
API Version: 2021-06-08
现在,在您的 Unity 脚本中,您需要进行如下更改:
private string DownloadString(string url)
{
using (WebClient client = new WebClient())
{
client.Headers.Add("Authorization", "SharedKey devstoreaccount1:<signature>");
client.Headers.Add("x-ms-date", "Sat, 21 Oct 2023 05:18:57 GMT");
client.Headers.Add("x-ms-version", "2021-06-08");
return client.DownloadString(url);
}
}
参考: