unity3d 从Unity中的Azurite中提取文件失败

mfpqipee  于 2023-10-24  发布在  其他
关注(0)|答案(1)|浏览(244)

bounty将在7天后过期。回答此问题可获得+150声望奖励。jason希望引起更多关注此问题:我需要一种方法从Azurite Blob容器中读取文件。我无法在Nuget上使用任何Azure存储库,因为我将在Unity中使用此代码,而Unity不支持这些库。

我正在尝试在我的Unity场景中使用Azure存储中的OBJ文件,我将作为网站应用程序运行。我运行了Azurite,并创建了一个包含文件的容器。我可以在Azure Storage Explorer中的Emulator->Blob Container->MyContainer下查看该文件。我创建了Azurite,运行此Docker编写脚本:

azurite:
    image: mcr.microsoft.com/azure-storage/azurite
    container_name: "azurite"
    hostname: azurite
    restart: always
    ports:
      - "10000:10000"
      - "10001:10001"
      - "10002:10002"

在Azure存储资源管理器中,我可以看到这是我的连接字符串:
return devstoreaccount 1; AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OuzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;DefaultEndpointsProtocol=http;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1; TableEndpoint = http://127.0.0.1:10001/devstoreaccount1;
当我在Azure Storage Explorer中复制文件的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..

编辑

@Venkatesan非常感谢你这个非常彻底的回应!我已经尝试使用你的代码并运行它,但我仍然得到相同的403错误。我已经将我的代码移到控制台应用程序中,只是为了测试目的。我不确定我是否使用了错误的帐户凭据或Docker是否有问题?我可以在docker中看到容器正在获取请求,但它仍然失败。
对于密钥,我使用在MS Azure存储资源管理器中指定的密钥,我假设这是默认密钥设置,因为我没有在Docker Compose中指定它:Eby 8vdM 02 xNOcqFlqUwJPLlmEtlCDXJ 1 OUzFT 50 uSRZ 6 IFsuFq 2UVErCz 4 I6 tq/K1 SZFPTOtr/KBHBeksoGMGw==
对于容器,我使用了在Docker Compose文件中定义的azurite的值。我注意到当Docker Compose运行时,它没有创建Blob容器,所以我创建了一个并将其称为azurite
然后对于URL,我只是使用了在Storage Explorer中右键单击图像时定义的URL,并复制URL:

http://127.0.0.1:10000/devstoreaccount1/azurite/MyFile.obj

所以我的请求看起来像这样:

using (WebClient client = new WebClient())
{   
   client.Headers.Add("Authorization", $"SharedKey devstoreaccount1:{authorization}");
   client.Headers.Add("x-ms-date", date);
   client.Headers.Add("x-ms-version", apiVersion);
            
 client.DownloadString("http://127.0.0.1:10000/devstoreaccount1/azurite/MyFile.obj");
}

但是当控制台应用程序运行时,我创建签名并将其传递进去,它仍然失败,并出现403错误。

bejyjqdl

bejyjqdl1#

System.Net.WebException:远程服务器返回错误:(403)服务器无法验证请求。请确保Authorization标头的值格式正确,包括签名。
当您在授权标头中传递不正确的签名并且丢失某些标头时,会发生上述错误。
在**DownloadString**函数中,您在授权头中传递了一个不正确的直接访问密钥,并且您还需要添加日期和x-ms-version。
header应该是这样的:

x-ms-version: 2014-02-14 
x-ms-date: Fri, 26 Jun 2015 23:39:12 GMT
Authorization: SharedKey myaccount:ctzMq410TV3wS7upTBcuxxxxx=

根据此MS-REQ,您只需要在授权头中传递签名。
要从访问密钥中获取签名、日期和版本,您可以使用以下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);
    }
}

参考:

Call REST API operations with Shared Key authorization

相关问题