在 Azure 文件服务 REST Api 上调用创建文件

Call Create File on Azure File Service REST Api

我正在尝试在 Azure 文件服务中创建一个文件: https://docs.microsoft.com/en-us/rest/api/storageservices/create-file

我已经看到并阅读了有关此问题的多个线程,但我无法弄清楚我的情况可能是什么问题...很可能我在请求中遗漏了一些我找不到的小东西.

我得到的错误:在 HTTP 请求中找到的 MAC 签名 (...) 与任何计算签名不同。

我用过的签名串:

PUT
\n
\n
\n
\n
text/plain // Content-Type
\n
\n
\n
\n
\n
\n
x-ms-content-length:1000
x-ms-date:Tue, 20 Apr 2021 19:23:30 GMT
x-ms-type:file
x-ms-version:2015-02-21
/account/share/test

授权header:

SharedKey account:XXXXXXXXXX

我使用 HMACSHA256 对授权 header 和签名字符串进行哈希处理,当我使用其他端点(列表共享:https://docs.microsoft.com/en-us/rest/api/storageservices/list-shares), but I can't make it work for the file. I've seen this topic AZURE File Service - Upload PDF through REST API 并且我相信我正在使用非常相似的请求,但没有成功...

感谢任何帮助:)

编辑: 我不确定我是否正确设置了内容 headers。例如, x-ms-content-length 是否应该放在 CanonicalizedHeaders 字符串中?

编辑2: 关于 Ivan Yang 写的,我使代码可以工作,但只有当我的 CanonicalizedHeaders 是这样构建的时候:

        CanonicalizedHeaders := 'x-ms-content-length:1200'
                + LF + 'x-ms-date:' + UTCDateTimeText
                + LF + 'x-ms-file-attributes:Archive' + LF + 'x-ms-file-creation-time:Now' + LF + 'x-ms-file-last-write-time:Now' + LF + 'x-ms-file-permission:Inherit'
                + LF + 'x-ms-type:file' + LF + 'x-ms-version:2019-02-02';

如果我按不同的顺序排列它们,它就会崩溃:

     CanonicalizedHeaders := 'x-ms-date:' + UTCDateTimeText + LF +
                                'x-ms-content-length:1200' + LF +
                                'x-ms-version:2019-02-02' + LF +
                                'x-ms-file-attributes:Archive' + LF +
                                'x-ms-file-creation-time:Now' + LF +
                                'x-ms-file-last-write-time:Now' + LF +
                                'x-ms-file-permission:Inherit' + LF +
                                'x-ms-type:file';

这怎么会有所不同?

您的签名字符串不正确(您遗漏了一些 "\n")。我使用的是 x-ms-version:2019-02-02 而不是旧的 x-ms-version:2015-02-21,正确的签名字符串应该如下所示:

           "PUT\n"
            + "\n" // content encoding
            + "\n" // content language
            + "\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-content-length:" + content_length
            + "\nx-ms-date:" + dt.ToString("R")
            + "\nx-ms-file-attributes:Archive" + "\nx-ms-file-creation-time:Now" + "\nx-ms-file-last-write-time:Now" + "\nx-ms-file-permission:Inherit"
            + "\nx-ms-type:file" + "\nx-ms-version:" + apiversion + "\n" // headers
            + "/{0}/{1}/{2}", Account, FileShare, FileName);

这里是 c# code 使用 create file api:

using System;
using System.Globalization;
using System.Net;
using System.Security.Cryptography;

namespace ConsoleApp25
{
    class Program
    {
        static void Main(string[] args)
        {
            string Account = "storage_account_name";
            string Key = "storage_account_key";
            string FileShare = "file_share_name";
            string FileName = "test555.txt";
            string apiversion = "2019-02-02";
            int content_length = 1200;
            string content_type = "text/plain";

            DateTime dt = DateTime.UtcNow;
            string StringToSign = String.Format("PUT\n"
                + "\n" // content encoding
                + "\n" // content language
                + "\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-content-length:" + content_length
                + "\nx-ms-date:" + dt.ToString("R")
                + "\nx-ms-file-attributes:Archive" + "\nx-ms-file-creation-time:Now" + "\nx-ms-file-last-write-time:Now" + "\nx-ms-file-permission:Inherit"
                + "\nx-ms-type:file" + "\nx-ms-version:" + apiversion + "\n" // headers
                + "/{0}/{1}/{2}", Account, FileShare, FileName);

            string auth = SignThis(StringToSign, Key, Account);
            string method = "PUT";
            string urlPath = string.Format("https://{0}.file.core.windows.net/{1}/{2}", Account, FileShare, FileName);
            Uri uri = new Uri(urlPath);
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
            request.Method = method;
            request.ContentLength = 0;

            request.Headers.Add("x-ms-content-length", $"{content_length}");
            request.Headers.Add("Content-Type", content_type);
            request.Headers.Add("x-ms-type", "file");
            request.Headers.Add("x-ms-date", dt.ToString("R"));
            request.Headers.Add("x-ms-version", apiversion);
            request.Headers.Add("x-ms-file-attributes", "Archive"); //note it is case-sensitive.
            request.Headers.Add("x-ms-file-permission", "Inherit");
            request.Headers.Add("x-ms-file-creation-time", "Now");
            request.Headers.Add("x-ms-file-last-write-time", "Now");
            request.Headers.Add("Authorization", auth);
           

            using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
            {
                //read the response code
                Console.WriteLine("the response is:" + response.StatusCode);
            }

            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;
        }

    }
}