如何验证 Azure 存储 blob 名称

Dan*_*ter 5 c# azure azure-storage azure-blob-storage

我正在实现一个 API 来在 Azure Blob 存储中存储文件。

我正在使用 Microsoft 库来验证容器和 blob 名称。

NameValidator.ValidateContainerName(containerName);
NameValidator.ValidateBlobName(blobFullName);
Run Code Online (Sandbox Code Playgroud)

然而,它返回的一些名称是有效的,尽管我知道他们自己的文档不是,当我尝试保存它们时,blob 存储返回 400 个错误的请求,正如预期的那样。因此,除了为什么 MS 验证库不完整的问题之外,我如何在 C# 中执行其余的验证?具体来说,我现在失败了

“一些 ASCII 或 Unicode 字符,如控制字符(0x00 到 0x1F、\u0081 等)”

我有一个文件名中带有 \u0081 的文件。剩下的无效字符是什么。他们将我们指向 ietf 文档,然后说其中“某些”字符是不允许的?哪个?只是所有控制字符?

为了清楚起见,这是返回 400 的部分

CloudBlockBlob blob = documentContainer.GetBlockBlobReference(blobFullName);
                await blob.UploadFromStreamAsync(fileStream, token).ConfigureAwait(false);
Run Code Online (Sandbox Code Playgroud)

谢谢你的帮助!

更新:我已经添加了这一点逻辑来至少检查控制字符。如果我能得到一些健壮的东西,我将针对 Microsoft 的验证代码发出 PR

if (blobFullName.ToCharArray().Any(c => Char.IsControl(c))) {
    throw new HissyFitException();  // or do other stuff to fail validation
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*uch 2

我现在编写了自己的实现来检查存储帐户名称、容器名称和 blob 名称的有效性。在我的实现中,整个名称必须以以下形式传递给方法:Storage_Account_name/Container_name/Blob_name,例如 mystorageaccount/containername/this/is_a/blob.jpg blob 名称可能包含“/”。

     // Use like this:

           public static bool IsBlobFilenameValid(string blobFilename)
           {
                // e. g. blobFilename = "mystorageaccount/containername/this/is_a/blob.jpg
                string storageAccount = GetStorageAccount(blobFilename);
                string container = GetContainer(blobFilename);
                string blobName = GetBlobFilename(blobFilename);

                if(string.IsNullOrWhiteSpace(storageAccount)
                    || string.IsNullOrWhiteSpace(container)
                    || string.IsNullOrWhiteSpace(blobName)
                    || !IsAzureBlobFilenameValid(blobFilename))
                {
                    return false;
                }
                return true;
        }

        private static bool IsAzureBlobFilenameValid(string filename)
        {
            if (filename.Count(c => c == '/') < 2)
            {
                return false;
            }
            var storageAccount = GetStorageAccount(filename);
            var container = GetContainer(filename);
            var blob = GetBlobFilename(filename);

            string patternAccount = @"^[a-z0-9]{3,24}$";
            string patternContainer = @"^[a-z0-9-]{3,63}$";
            string patternBlob = @"^.{1,1024}$";

            if (!Regex.IsMatch(container, patternContainer)
                || !Regex.IsMatch(storageAccount, patternAccount)
                || !Regex.IsMatch(blob, patternBlob))
            {
                return false;
            }
            return true;
        }

        private static string GetStorageAccount(string file)
        {

            int charLocation = file.IndexOf('/', StringComparison.Ordinal);
            if (charLocation > 0)
            {
                return file.Substring(0, charLocation);
            }
            return string.Empty;

        }

        private static string GetContainer(string file)
        {
            int charLocation = IndexOfSecond(file, "/");
            if (charLocation > 0)
            {
                return file.Substring(0, charLocation);
            }
            return string.Empty;
        }

        private static string GetBlobFilename(string file)
        {
            int charLocation = IndexOfSecond(file, "/");
            if (charLocation > 0)
            {
                return file.Substring(charLocation + 1, file.Length - (charLocation + 1));
            }
            return string.Empty;
        }

        private static int IndexOfSecond(string theString, string toFind)
        {
            int first = theString.IndexOf(toFind);

            if (first == -1) return -1;

            // Find the "next" occurrence by starting just past the first
            return theString.IndexOf(toFind, first + 1);
        }

Run Code Online (Sandbox Code Playgroud)