Azure存储SAS令牌生成-签名不匹配

时间:2020-02-19 16:10:36

标签: azure

我已经为这个问题苦苦挣扎了3天。我真的很感谢您的帮助。

我正在尝试创建SAS令牌以动态访问Azure存储Blob,该令牌会生成,但是我一直收到此错误: Signature did not match. String to sign used was ...

从azure门户创建SAS令牌工作正常,但是我尝试使用多种方法在代码中生成它,即Micrtosoft.Azure.Storage库:

private static string GetBlobSasUri(CloudBlobContainer container, string blobName)
{
    string sasBlobToken;

    // Get a reference to a blob within the container.
    // Note that the blob may not exist yet, but a SAS can still be created for it.
    CloudBlockBlob blob = container.GetBlockBlobReference(blobName);


    // Create a new access policy and define its constraints.
    // Note that the SharedAccessBlobPolicy class is used both to define the parameters of an ad hoc SAS, and
    // to construct a shared access policy that is saved to the container's shared access policies.
    SharedAccessBlobPolicy adHocSAS = new SharedAccessBlobPolicy()
    {
        // When the start time for the SAS is omitted, the start time is assumed to be the time when the storage service receives the request.
        // Omitting the start time for a SAS that is effective immediately helps to avoid clock skew.
        SharedAccessStartTime = DateTime.UtcNow.AddHours(-24),
        SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24),
        Permissions = SharedAccessBlobPermissions.Read //| SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Create
    };

    // Generate the shared access signature on the blob, setting the constraints directly on the signature.
    sasBlobToken = blob.GetSharedAccessSignature(adHocSAS);

    Console.WriteLine("SAS for blob (ad hoc): {0}", sasBlobToken);
    Console.WriteLine();

    // Return the URI string for the container, including the SAS token.
    return blob.Uri + sasBlobToken;
}

这已经尝试了好几次,第二天停止运行。.我在本地IIS和Azure上对其进行了测试,在本地却从未起作用。

我也尝试过自己创建令牌,生成令牌并对其进行签名,但是仍然存在相同的问题..这是签名的代码:

 public static string generateSAS(Uri resourceUri, string accountKey, string accountName, StorageFile f)
        {

            string
                sr = "b",
                sp = "r",
                st = DateTime.Now.AddHours(-50).ToString("yyyy-MM-ddTH:MM:ssZ"),
                se = DateTime.Now.AddHours(50).ToString("yyyy-MM-ddTH:MM:ssZ"),
                sv = "2016-05-31"; //"2019-07-07"

            string blobUri = $"https://{accountName}.blob.core.windows.net/{f.Model.Container}/{f.Model.FileName}";

            string stringToSign = string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n{5}\n{6}\n{7}\n{8}\n{9}\n{10}\n{11}\n{12}", new object[]
            {
                "r",
                st,
                se,
                GetCanonicalizedResource(new Uri(blobUri), accountName),
                string.Empty,
                string.Empty,
                string.Empty,
                sv,
                sr,
                string.Empty,
                string.Empty,
                string.Empty,
                string.Empty
            });

            var sas = GetHash(stringToSign, accountKey);

            var token =
                $"?sv={sv}&sr=b&sig={HttpUtility.UrlEncode(sas)}&st={HttpUtility.UrlEncode(st)}&se={HttpUtility.UrlEncode(se)}&sp=r";


            return blobUri + token;
        }

        private static string GetHash(string stringToSign, string key)
        {
            byte[] keyValue = Convert.FromBase64String(key);

            using (HMACSHA256 hmac = new HMACSHA256(keyValue))
            {
                return Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
            }
        }



private static string GetCanonicalizedResource(Uri address, string storageAccountName)
        {
             // The absolute path is "/" because for we're getting a list of containers.
            StringBuilder sb = new StringBuilder("/").Append("blob").Append("/").Append(storageAccountName).Append(address.AbsolutePath);
            return sb.ToString();

        }

我已经阅读了文档,并认为该问题可能是版本问题,因此我尝试使用最新版本和之前的某些版本,但无济于事。

我尝试不使用和添加其他参数,根本没有任何效果。

我也被认为是时钟问题,但是到目前为止,我已经将时钟调整为每天的每个小时,并且已经在Azure上的应用服务上进行了测试,该服务位于“ UK South”,在那里的C#代码用了不到一天的时间。

非常感谢您的帮助!谢谢

编辑 使用我手动对其进行自我签名的RESTful版本代码,即“ toSignString”:

r
2020-02-17T14:02:56Z
2020-02-21T18:02:56Z
/blob/<accountName>/<contaioner1>/<subContainer2>/<subContainer3>/file.v



2016-05-31
b




这是完整的Uri:

https://<account>.blob.core.windows.net/<contaioner1>/<subContainer2>/<subContainer3>/file.v?
sv=2016-05-31&sr=b&sig=hI7MH0pT05cDpga2bMkanR%2b77CeocgttygDJbkRw6EM%3d&st=2020-02-17T14%3a02%3a56Z&se=2020-02-21T18%3a02%3a56Z&sp=r

1 个答案:

答案 0 :(得分:1)

这已经工作了一天,然后停止工作了。我测试了 它在我的本地IIS和azure上都无法正常工作。

这是预期的行为,因为您将SAS令牌到期设置为距当前日期/时间24小时(以UTC为单位):

mix.js('resources/js/app.js', 'public/js')
.sass(commonSassFile, cssPublicDir+'/app_blue.css', {
    data: '$theme-bg-primary: #1450d9;'
})
.sass(commonSassFile, cssPublicDir+'/app_red.css', {
    data: '$theme-bg-primary: #ba0000;'
});

如果希望SAS URL更长的工作时间,则需要指定将来的有效期。

关于第二个问题(手动创建SAS令牌),我认为您的SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24), 方法存在问题。根据{{​​3}},它应采用以下格式:

GetCanonicalizedResource

字符串的canonicalizedresource部分是通向的规范路径 签名的资源。它必须包含服务名称(blob,表, 队列或文件)(版本为2015-02-21或更高版本),存储帐户 名称和资源名称,并且必须经过URL解码。

基于此,请尝试以下代码:

/blob/<account-name>/<container-name>/<blob-name>

更新

让我花点时间找出问题所在:),但终于可以了。我发现了许多问题:

  1. 您格式化日期的格式不正确。它应为private static string GetCanonicalizedResource(Uri address, string storageAccountName) { // The absolute path is "/" because for we're getting a list of containers. StringBuilder sb = new StringBuilder("/").Append("blob").Append("/").Append(storageAccountName).Append("/").Append(address.AbsolutePath); return sb.ToString(); } ,但您要以yyyy-MM-ddTHH:MM:ssZ格式对其进行格式化。如果您注意到,它会丢失额外的yyyy-MM-ddTH:MM:ssZ
  2. 您使用的是H签名版本,但2016-05-31中不包括签名资源(在您的情况下为b),但您要包括该签名资源。但是,它应该包含在您的SAS URL中。
  3. 您要签名的字符串缺少stringToSign参数。

根据文档,这就是构造content-language (rscl)的方式:

stringToSign

基于此,这应该是您的代码:

StringToSign = signedpermissions + "\n" +  
               signedstart + "\n" +  
               signedexpiry + "\n" +  
               canonicalizedresource + "\n" +  
               signedidentifier + "\n" +  
               signedIP + "\n" +  
               signedProtocol + "\n" +  
               signedversion + "\n" +  
               rscc + "\n" +  
               rscd + "\n" +  
               rsce + "\n" +  
               rscl + "\n" +  
               rsct

尝试一下,它应该可以工作。

相关问题