練習 - 使用共用存取簽章來委派對 Azure 儲存體的存取權

已完成

Azure 儲存體讓您能夠以共用金鑰、共用存取簽章 (SAS) 或 Microsoft Entra ID 授與檔案的存取權。 使用 SAS,您可以控制用戶端能對檔案執行的動作,以及時間長短。

貴公司的影像診斷系統會透過共用金鑰在內部存取其患者影像。 您需要建立 API,讓協力廠商能夠存取診斷影像。 您會在自己的 Web 應用程式上建立測試頁面,以查看 SAS 如何協助您為協力廠商用戶端授與安全的存取權。

在此練習中,您會建立一個儲存體帳戶,並上傳一些範例患者影像。 您會部署小組現有的 Web 應用程式,並測試此應用程式能否存取儲存體。 最後一個步驟是新增 C# 與 JavaScript 程式碼,隨需產生 SAS 權杖以安全地檢視影像。

Screenshot of your company's patient diagnostic image system showing three images.

建立儲存體帳戶及上傳影像

  1. 使用 Azure Cloud Shell,輸入下列程式碼,以建立患者影像的儲存體帳戶。 程式碼會產生儲存體帳戶名稱。

    export STORAGENAME=medicalrecords$RANDOM
    
    az storage account create \
        --name $STORAGENAME \
        --access-tier hot \
        --kind StorageV2 \
        --resource-group "<rgn>[sandbox resource group name]</rgn>"
    
  2. 在儲存體帳戶底下,建立用來儲存影像的容器。

    az storage container create \
        --name patient-images \
        --account-name $STORAGENAME \
        --public-access off
    
  3. 複製小組現有的 Web 應用程式。 此存放庫包含小組用來測試的範例影像。

    git clone https://github.com/MicrosoftDocs/mslearn-control-access-to-azure-storage-with-sas.git sas
    
  4. 使用 Azure CLI 的 upload-batch 命令,將影像上傳至您的儲存體帳戶。

    az storage blob upload-batch \
        --source sas \
        --destination patient-images \
        --account-name $STORAGENAME \
        --pattern *.jpg
    

測試患者診斷影像系統

  1. 在程式碼編輯器中,開啟 appsettings.json 檔案,以便新增儲存體帳戶的連接字串。

    code sas/appsettings.json
    
  2. 在 Cloud Shell 中,輸入下列程式碼,以取得儲存體帳戶的連接字串。

    az storage account show-connection-string --name $STORAGENAME
    

    您應該會看到下列格式的回應:

    {
      "connectionString": "DefaultEndpointsProtocol=https;EndpointSuffix=core.windows.net;AccountName=medicalrecords3215;AccountKey=UGLNuJWUBtodz+VbhhFcMwkzDpX49Wf7FxtuQDTOHhH+LpCtSQ2LBP0Ju8TQby5CeOt7DMYBgH45SX9yFwqPvA=="
    }
    

    複製 connectionString 值,包括引號。

  3. 在程式碼編輯器中,將 ConnectionString 值 "[connection string]" 取代為您複製的字串。

  4. 複製連接字串主體中 AccountName= 的值。

  5. 將 AccountName 參數的值取代為您複製的帳戶名稱值。

  6. 複製連接字串主體中 AccountKey= 的值 (不包含引號)。 務必在值結尾包含 ==

  7. 將 AccountKey 參數的值取代為您複製的帳戶金鑰值。

  8. appsettings.json 檔案現在看起來應該類似這個輸出。

    {
      "Logging": {
        "LogLevel": {
          "Default": "Warning"
        }
      },
      "AllowedHosts": "*",
      "StorageAccount": {
        "ConnectionString": "DefaultEndpointsProtocol=https;AccountName=medicalrecords3215;AccountKey=UGLNuJWUBtodz+VbhhFcMwkzDpX49Wf7FxtuQDTOHhH+LpCtSQ2LBP0Ju8TQby5CeOt7DMYBgH45SX9yFwqPvA==;EndpointSuffix=core.windows.net",
        "Container" : "patient-images",
        "AccountName":"medicalrecords3215",
        "AccountKey":"UGLNuJWUBtodz+VbhhFcMwkzDpX49Wf7FxtuQDTOHhH+LpCtSQ2LBP0Ju8TQby5CeOt7DMYBgH45SX9yFwqPvA=="
      }  
    }
    
  9. 選取 Ctrl+S,然後選取 Ctrl+Q,以儲存並關閉程式碼編輯器。

  10. 開啟連接埠,以便您可以 Web 應用程式在 Cloud Shell 中執行時,存取 Web 應用程式。

    curl -X POST http://localhost:8888/openPort/8000;
    

    此命令會傳回可在其中存取您應用程式的 url

    {"message":"Port 8000 is open","url":"https://gateway11.northeurope.console.azure.com/n/cc-4016c848/cc-4016c848/proxy/8000/"}
    
  11. 執行應用程式。

    cd sas
    dotnet run
    

    編譯應用程式之後,Cloud Shell 主控台會顯示類似下列範例的詳細資料。

    Hosting environment: Development
    Content root path: /home/<yourusername>/sas
    Now listening on: https://localhost:8001
    Now listening on: http://localhost:8000
    Application started. Press Ctrl+C to shut down.
    
  12. 在瀏覽器中,貼上先前的 cURL 命令所傳回的 URL。 確定位址的結尾包含正斜線 (/)。

    URL 應該是此格式: https://gateway11.northeurope.console.azure.com/n/cc-4016c848/cc-4016c848/proxy/8000/

    如果系統提示您登入,請重新整理瀏覽器視窗。 Lamna 醫療保健患者診斷影像系統隨即出現。

  13. 選取 [Get all patients] \(取得所有患者資料\),以檢視儲存在儲存體帳戶中的所有影像。

新增程式碼以建立 SAS

  1. 在 Cloud Shell 中,選取 Ctrl+C 以停止 Web 應用程式。

  2. 讓我們增強 PatientRecordController 類別以建立隨需 SAS,並將其傳回至 Web 應用程式的前端。

  3. 輸入下列程式碼,以在程式碼編輯器中開啟 PatientRecordController.cs 檔案。

    code Controllers/PatientRecordController.cs
    
  4. 將下列程式碼新增至 GET PatientRecord/patient-nnnnnn 方法下的類別底部。

    // GET PatientRecord/patient-nnnnnn/secure
    [HttpGet("{Name}/{secure}")]
    public PatientRecord Get(string name, string flag)
    {
        BlobClient blob = _container.GetBlobClient(name);
        return new PatientRecord { name=blob.Name, imageURI=blob.Uri.AbsoluteUri, sasToken=GetBlobSas(blob) };
    }
    

    此方法會傳回所要求的患者影像,以及可用來存取該影像的 SAS。

  5. 新增將為 Blob 建立 SAS 的方法。

    // Build a SAS token for the given blob
    private string GetBlobSas(BlobClient blob)
    {
        // Create a user SAS that only allows reading for a minute
        BlobSasBuilder sas = new BlobSasBuilder 
        {
            BlobContainerName = blob.BlobContainerName,
            BlobName = blob.Name,
            Resource = "b",
            ExpiresOn = DateTimeOffset.UtcNow.AddMinutes(1)
        };
        // Allow read access
        sas.SetPermissions(BlobSasPermissions.Read);
    
        // Use the shared key to access the blob
        var storageSharedKeyCredential = new StorageSharedKeyCredential(
            _iconfiguration.GetValue<string>("StorageAccount:AccountName"),
            _iconfiguration.GetValue<string>("StorageAccount:AccountKey")
        );
    
        return '?' + sas.ToSasQueryParameters(storageSharedKeyCredential).ToString();
    }
    

    此方法會使用傳遞的 BlobClient 物件來建立 BlobSasBuilder,以產生唯讀的 SAS,並在一分鐘內到期。

  6. 選取 Ctrl+S 以儲存檔案,然後選取 Ctrl+Q 以結束編輯器。

新增程式碼以使用 SAS

讓我們將程式碼新增至網頁,以要求影像的 SAS。

  1. 輸入下列命令,以編輯 external.cshtml 頁面。

    code Pages/external.cshtml
    
    
  2. 在檔案結尾附近,在 #btn-submit 的點選接聽程式中,修改 $.get 行以新增 + '/secure'

    $('#btn-submit').click(function(){
        $('#result').empty();
        $.get('api/PatientRecords/' + $('#patientID').val() + '/secure', function (data) {
            var imageURL = data.imageURI + $('#sasKey').val();
            $('#result').html('<img id="patientScan" class="alert alert-success" src="' + imageURL + '" alt="patient scan" onerror="this.classList.remove(\'alert-success\'); this.classList.add(\'alert-danger\')"//>');
        }, 'json');
    });
    
  3. 在檔案底部的 #btn-submit 點選接聽程式函式下方,於 </script> 標籤上方,新增下列程式碼:

    $('#btn-getKey').click(function(){
        $.get('api/PatientRecords/' + $('#patientID').val() + '/secure', function (data) {
            $('#sasKey').val(data.sasToken);
        }, 'json');
    });
    

    此 jQuery 程式碼會在 btn-getKey 按鈕上新增 click 接聽程式。 此程式碼會對適用於指定影像檔案的新安全 URL 執行 Ajax 呼叫。 當其傳回時,會在金鑰輸入方塊中填入 SAS。

  4. 選取 Ctrl+S 以儲存變更,然後選取 Ctrl+Q 以結束編輯器。

測試變更

  1. 執行已更新的應用程式。

    dotnet run
    
  2. 在瀏覽器中,重新整理網站的索引標籤。 選取 [Get all patients] \(取得所有患者資料\),然後複製其中一個影像檔案名稱。

  3. 在網頁頂端的功能表中,選取 [External companies] \(外部公司\)。

  4. 將檔案名稱貼入 [Patient image filename] (患者影像檔案名稱) 欄位。

  5. 選取 [檢視掃描]。 因為您尚未建立 SAS,所以無法存取患者掃描影像。

    注意

    如果您在瀏覽器中檢視主控台,即會看到 Web 伺服器傳回 404 錯誤碼訊息。

  6. 選取 [取得金鑰],這應該用 SAS 來填入 [金鑰] 欄位。

  7. 選取 [檢視掃描]。 患者的診斷影像應該會隨即出現。

    Screenshot of API for external companies showing a patient's image.

  8. 在瀏覽器中,以滑鼠右鍵按一下影像,然後複製影像位址。

  9. 開啟新的瀏覽器索引標籤、在網址列中貼上複製的影像位址,然後按 Enter。 如果自您建立 SAS 後已超過一分鐘,您應會看到一則錯誤訊息。 如果小於一分鐘,則應會顯示影像。

    注意

    您可能需要重新整理網頁。

    <Error>
        <Code>AuthenticationFailed</Code>
        <Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly, including the signature.
        RequestId:03eda893-f01e-0028-2d73-c5c947000000
        Time:2021-01-07T16:02:55.3752851Z</Message>
        <AuthenticationErrorDetail>Signed expiry time [Tue, 07 Jan 2021 16:02:00 GMT] must be after signed start time [Tue, 07 Jan 2021 16:02:55 GMT]</AuthenticationErrorDetail>
    </Error>
    

    注意

    若要從某些瀏覽器檢視此錯誤訊息,您可能需要開啟不會快取影像的新瀏覽器視窗。

  10. 在 Cloud Shell 中,選取 Ctrl+C 以結束 Web 應用程式。