2013-10-07 45 views
0

我有一個相當簡單的方法,它使用NEW Storage API創建SAS並將blob從一個容器複製到另一個容器。使用Microsoft.WindowsAzure.Storage創建共享訪問令牌返回403

我想用這個來複制blob BETWEEN STORAGE ACCOUNTS。因此,我有兩個存儲帳戶,具有完全相同的容器,並且我試圖將存儲帳戶的容器中的一個塊複製到另一個存儲帳戶的容器。

我不知道SDK是否爲此而構建,但看起來這將是一種常見的情況。

一些額外的信息:

  1. 我創建目標容器的令牌。 是否需要在源和目標上創建該令牌?註冊令牌需要時間嗎?我是否需要爲每個請求創建它,或者每個標記「生命期」只需創建一次?

我應該提到一個403是一個未經授權的結果http錯誤代碼。

private static string CreateSharedAccessToken(CloudBlobClient blobClient, string containerName) 
    { 
     var container = blobClient.GetContainerReference(containerName); 
     var blobPermissions = new BlobContainerPermissions(); 

     // The shared access policy provides read/write access to the container for 10 hours: 

     blobPermissions.SharedAccessPolicies.Add("SolutionPolicy", new SharedAccessBlobPolicy() 
     { 
      // To ensure SAS is valid immediately we don’t set start time 
      // so we can avoid failures caused by small clock differences: 

      SharedAccessExpiryTime = DateTime.UtcNow.AddHours(1), 
      Permissions = SharedAccessBlobPermissions.Write | 
          SharedAccessBlobPermissions.Read 
     }); 


     blobPermissions.PublicAccess = BlobContainerPublicAccessType.Blob; 
     container.SetPermissions(blobPermissions); 

     return container.GetSharedAccessSignature(new SharedAccessBlobPolicy(), "SolutionPolicy"); 

    } 

下我使用此標記調用拷貝操作,它返回一個403行:

var uri = new Uri(srcBlob.Uri.AbsoluteUri + blobToken); 
      destBlob.StartCopyFromBlob(uri); 

我Azure.Storage的版本是2.1.0.2。

這裏是萬一完全複製方法,可以幫助:

private static void CopyBlobs(
     CloudBlobContainer srcContainer, string blobToken, 
     CloudBlobContainer destContainer) 
    { 
     var srcBlobList 
      = srcContainer.ListBlobs(string.Empty, true, BlobListingDetails.All); // set to none in prod (4perf) 

     //// get the SAS token to use for all blobs 
     //string token = srcContainer.GetSharedAccessSignature(
     // new SharedAccessBlobPolicy(), "SolutionPolicy"); 

     bool pendingCopy = true; 

     foreach (var src in srcBlobList) 
     { 
      var srcBlob = src as ICloudBlob; 

      // Determine BlobType: 

      ICloudBlob destBlob; 
      if (srcBlob.Properties.BlobType == BlobType.BlockBlob) 
      { 
       destBlob = destContainer.GetBlockBlobReference(srcBlob.Name); 
      } 
      else 
      { 
       destBlob = destContainer.GetPageBlobReference(srcBlob.Name); 
      } 

      // Determine Copy State: 

      if (destBlob.CopyState != null) 
      { 
       switch (destBlob.CopyState.Status) 
       { 
        case CopyStatus.Failed: 
         log.Info(destBlob.CopyState); 
         break; 

        case CopyStatus.Aborted: 
         log.Info(destBlob.CopyState); 
         pendingCopy = true; 
         destBlob.StartCopyFromBlob(destBlob.CopyState.Source); 
         return; 

        case CopyStatus.Pending: 
         log.Info(destBlob.CopyState); 
         pendingCopy = true; 
         break; 
       } 
      } 


      // copy using only Policy ID: 
      var uri = new Uri(srcBlob.Uri.AbsoluteUri + blobToken); 
      destBlob.StartCopyFromBlob(uri); 


      //// copy using src blob as SAS 
      //var source = new Uri(srcBlob.Uri.AbsoluteUri + token); 
      //destBlob.StartCopyFromBlob(source); 

     } 
    } 

最後的帳戶和客戶端(審覈)代碼:

 var credentials = new StorageCredentials("BAR", "FOO"); 
     var account = new CloudStorageAccount(credentials, true); 
     var blobClient = account.CreateCloudBlobClient(); 
     var sasToken = CreateSharedAccessToken(blobClient, "content"); 

當我使用REST客戶端,這似乎工作... 有任何想法嗎?

+0

多少時間你對SAS的創建和複製使用的URL之間發生? – MikeWo

+0

它瞬間發生;我稱之爲SAS方法,稍後再調用StartCopyFromBlob()api調用。它可能與編碼uri有關嗎?我看到過有關REST客戶端可以工作的報告,但Azure SDK失敗了,但沒有看到任何解決方案。 – nocarrier

+0

我剛剛意識到問題在於它是在兩個不同的賬戶之間進行 - 我認爲這意味着我需要兩個賬戶(目的地和來源)的信用卡?我不確定SAS如何在Blob內容服務器上工作.. – nocarrier

回答

0

此任務不需要共享訪問令牌。我結束了兩個賬戶,它工作正常:

 var accountSrc = new CloudStorageAccount(credsSrc, true); 
     var accountDest = new CloudStorageAccount(credsSrc, true); 

     var blobClientSrc = accountSrc.CreateCloudBlobClient(); 
     var blobClientDest = accountDest.CreateCloudBlobClient(); 


     // Set permissions on the container. 
     var permissions = new BlobContainerPermissions {PublicAccess = BlobContainerPublicAccessType.Blob}; 
     srcContainer.SetPermissions(permissions); 
     destContainer.SetPermissions(permissions); 


    //grab the blob 
     var sourceBlob = srcContainer.GetBlockBlobReference("FOO"); 
     var destinationBlob = destContainer.GetBlockBlobReference("BAR"); 

     //create a new blob 
     destinationBlob.StartCopyFromBlob(sourceBlob); 
+0

如果你擁有這兩個賬戶,那麼是的,你做的很好。我猜測SAS會發生什麼事是時鐘漂移。當你創建SAS時,你給它一個到期,但不是開始,這意味着它立即開始。服務器上的時鐘可能會相互偏移,這意味着SAS可能無法立即工作。答案是過去幾分鐘開始創建SAS。 – MikeWo

0

由於兩個CloudStorageAccount對象指向同一個帳戶,未安裝SAS令牌複製,你也提到會工作得很好。

另一方面,您需要可公開訪問的blob或SAS令牌從其他帳戶複製。所以你嘗試的是正確的,但是你建立了一個容器級別的訪問策略,這個策略可能需要30秒才能生效,同樣也記錄在MSDN中。在此間隔期間,與存儲的訪問策略關聯的SAS令牌將失敗,並顯示狀態碼403(禁止),直到訪問策略激活。

我還想指出的另一件事是;當您調用Get * BlobReference來創建新的Blob對象時,只有在執行GET/HEAD操作(例如FetchAttributes)之後,纔會填充CopyState屬性。

1

也是這個問題考慮:

var uri = new Uri(srcBlob.Uri.AbsoluteUri + blobToken); 

也許你正在呼籲URI的「的ToString」方法產生的URL的「人類redable」版本。如果blobToken包含特殊字符(例如「+」),則會導致存儲服務器上的令牌格式錯誤,導致拒絕訪問。

使用這個代替:

String uri = srcBlob.Uri.AbsoluteUri + blobToken; 
相關問題