Creare un token di firma di accesso condiviso della delega utente con Archiviazione BLOB di Azure e JavaScript

Questo articolo illustra come creare un token di firma di accesso condiviso della delega utente nella libreria client di Archiviazione BLOB di Azure v12 per JavaScript. Una firma di accesso condiviso di delega utente, introdotta con la versione 2018-11-09, è protetta con le credenziali di Microsoft Entra ed è supportata solo per il servizio BLOB:

  • Concedere l'accesso a un contenitore esistente.
  • Concedere l'accesso per creare, usare ed eliminare BLOB.

Per creare una firma di accesso condiviso della delega utente, un client deve disporre delle autorizzazioni per chiamare l'operazione blobServiceClient.getUserDelegationKey. La chiave restituita da questa operazione viene usata per effettuare la firma di accesso condiviso della delega utente. All'entità di sicurezza che chiama questa operazione deve essere assegnato un ruolo Controllo degli accessi in base al ruolo che include Microsoft.Storage/storageAccounts/blobServices/generateUserDelegationKey/action.

Le autorizzazioni concesse a un client che possiede la firma di accesso condiviso sono l'intersezione delle autorizzazioni concesse all'entità di sicurezza che ha richiesto la chiave di delega utente e delle autorizzazioni concesse alla risorsa nel token di firma di accesso condiviso nel campo autorizzazioni firmato (sp). Se non viene concessa un'autorizzazione all'entità di sicurezza tramite il controllo degli accessi in base al ruolo anche nel token di firma di accesso condiviso, tale autorizzazione non viene concessa al client che tenta di usare la firma di accesso condiviso per accedere alla risorsa.

I frammenti di codice di esempio sono disponibili in GitHub come file eseguibili Node.js.

Pacchetto (npm) | Esempi | Riferimento API | Codice sorgente della raccolta | Inviare commenti e suggerimenti

Procedure consigliate per i token di firma di accesso condiviso della delega utente

Poiché chiunque abbia il token di firma di accesso condiviso può usarlo per accedere al contenitore e ai BLOB, è necessario definire il token di firma di accesso condiviso con le autorizzazioni più restrittive che consentano comunque al token di completare le attività necessarie.

Procedure consigliate per i token di firma di accesso condiviso

Usare DefaultAzureCredential nel Cloud di Azure

Per eseguire l'autenticazione in Azure, senza segreti, configurare l'identità gestita. Questo approccio consente al codice di usare DefaultAzureCredential.

Per configurare l'identità gestita per il Cloud di Azure:

  • Creare un'identità gestita
  • Impostare i ruoli di archiviazione appropriati per l'identità
  • Configurare l'ambiente Azure per l'uso dell'identità gestita

Al termine di queste due attività, usare DefaultAzureCredential anziché una stringa di connessione o una chiave dell'account. Questo approccio consente a tutti gli ambienti di usare esattamente lo stesso codice sorgente senza il problema di usare segreti nel codice sorgente.

Usare DefaultAzureCredential nello sviluppo locale

Nell'ambiente di sviluppo locale, l'identità di Azure (l'account personale o di sviluppo usato per accedere al portale di Azure) deve eseguire l'autenticazione in Azure per usare lo stesso codice nei runtime locali e cloud.

Contenitore: aggiungere le dipendenze necessarie all'applicazione

Includere le dipendenze necessarie per creare un token di firma di accesso condiviso del contenitore.

const {
    DefaultAzureCredential
} = require('@azure/identity');
const {
    ContainerClient,
    BlobServiceClient,
    ContainerSASPermissions,
    generateBlobSASQueryParameters,
    SASProtocol
} = require('@azure/storage-blob');

// used for local environment variables
require('dotenv').config();

Contenitore: ottenere le variabili di ambiente

Il nome dell'account di archiviazione BLOB e il nome del contenitore sono i valori minimi necessari per creare un token di firma di accesso condiviso del contenitore:

// Get environment variables for DefaultAzureCredential
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;
const containerName = process.env.AZURE_STORAGE_BLOB_CONTAINER_NAME;

Creare una firma di accesso condiviso con DefaultAzureCredential

Per creare un token di firma di accesso condiviso con DefaultAzureCredential sono necessari i passaggi concettuali seguenti:

  • Configurare DefaultAzureCredential
    • Sviluppo locale: usare l'identità personale e impostare i ruoli per l'archiviazione
    • Cloud di Azure: creare un'identità gestita
  • Usare DefaultAzureCredential per ottenere la chiave di delega utente con UserDelegationKey
  • Usare la chiave di delega utente per costruire il token di firma di accesso condiviso con i campi appropriati con generateBlobSASQueryParameters

Contenitore: creare un token di firma di accesso condiviso con DefaultAzureCredential

Con l'identità configurata, usare il codice seguente per creare token di firma di accesso condiviso di delega utente per un account e un contenitore esistenti:

// Server creates User Delegation SAS Token for container
async function createContainerSas() {

    // Get environment variables
    const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;
    const containerName = process.env.AZURE_STORAGE_BLOB_CONTAINER_NAME;

    // Best practice: create time limits
    const TEN_MINUTES = 10 * 60 * 1000;
    const NOW = new Date();

    // Best practice: set start time a little before current time to 
    // make sure any clock issues are avoided
    const TEN_MINUTES_BEFORE_NOW = new Date(NOW.valueOf() - TEN_MINUTES);
    const TEN_MINUTES_AFTER_NOW = new Date(NOW.valueOf() + TEN_MINUTES);

    // Best practice: use managed identity - DefaultAzureCredential
    const blobServiceClient = new BlobServiceClient(
        `https://${accountName}.blob.core.windows.net`,
        new DefaultAzureCredential()
      );

    // Best practice: delegation key is time-limited  
    // When using a user delegation key, container must already exist 
    const userDelegationKey = await blobServiceClient.getUserDelegationKey(
        TEN_MINUTES_BEFORE_NOW, 
        TEN_MINUTES_AFTER_NOW
    );

    // Need only list permission to list blobs 
    const containerPermissionsForAnonymousUser = "l";

    // Best practice: SAS options are time-limited
    const sasOptions = {
        containerName,                                           
        permissions: ContainerSASPermissions.parse(containerPermissionsForAnonymousUser), 
        protocol: SASProtocol.HttpsAndHttp,
        startsOn: TEN_MINUTES_BEFORE_NOW,
        expiresOn: TEN_MINUTES_AFTER_NOW
    };
 
    const sasToken = generateBlobSASQueryParameters(
        sasOptions,
        userDelegationKey,
        accountName 
    ).toString();

    return sasToken;
}

Il codice del server precedente crea un flusso di valori per creare il token di firma di accesso condiviso del contenitore:

Dopo aver creato il token di firma di accesso condiviso del contenitore, è possibile fornirlo al client che lo utilizzerà. Il client può quindi usarlo per elencare i BLOB in un contenitore. Un esempio di codice client illustra come testare la firma di accesso condiviso come consumer.

Contenitore: usare il token di firma di accesso condiviso

Dopo aver creato il token di firma di accesso condiviso del contenitore, usare il token. Come esempio di uso del token di firma di accesso condiviso, è possibile:

  • Costruire un URL completo, inclusi il nome del contenitore e la stringa di query. La stringa di query è il token di firma di accesso condiviso.
  • Creare un ContainerClient con l'URL del contenitore.
  • Usare il client: in questo esempio elencare i BLOB nel contenitore con listBlobsFlat.
// Client or another process uses SAS token to use container
async function listBlobs(sasToken){

    // Get environment variables
    const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;
    const containerName = process.env.AZURE_STORAGE_BLOB_CONTAINER_NAME;
    
    // Create Url
    // SAS token is the query string with typical `?` delimiter
    const sasUrl = `https://${accountName}.blob.core.windows.net/${containerName}?${sasToken}`;
    console.log(`\nContainerUrl = ${sasUrl}\n`);

    // Create container client from SAS token url
    const containerClient = new ContainerClient(sasUrl);

    let i = 1;

    // List blobs in container
    for await (const blob of containerClient.listBlobsFlat()) {
        console.log(`Blob ${i++}: ${blob.name}`);
    }    
}

BLOB: aggiungere le dipendenze necessarie all'applicazione

Includere le dipendenze necessarie per creare n token di firma di accesso condiviso BLOB.

const {
    DefaultAzureCredential
} = require('@azure/identity');
const {
    BlockBlobClient,
    BlobServiceClient,
    BlobSASPermissions,
    generateBlobSASQueryParameters,
    SASProtocol
} = require('@azure/storage-blob');

// used for local environment variables
require('dotenv').config();

BLOB: ottenere le variabili di ambiente

Il nome dell'account di archiviazione BLOB e il nome del contenitore sono i valori minimi necessari per creare un token di firma di accesso condiviso del BLOB:

const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;
const containerName = process.env.AZURE_STORAGE_BLOB_CONTAINER_NAME;

Quando è necessario creare un token di firma di accesso condiviso BLOB, è necessario avere il nome del BLOB per creare il token di firma di accesso condiviso. Tale nome verrà predeterminato, ad esempio un nome BLOB casuale, un nome BLOB inviato dall'utente o un nome generato dall'applicazione.

// Create random blob name for text file
const blobName = `${(0|Math.random()*9e6).toString(36)}.txt`;

BLOB: creare un token di firma di accesso condiviso con DefaultAzureCredential

Con l'identità configurata, usare il codice seguente per creare token di firma di accesso condiviso di delega utente per un account e un contenitore esistenti:

// Server creates User Delegation SAS Token for blob
async function createBlobSas(blobName) {

    // Get environment variables
    const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;
    const containerName = process.env.AZURE_STORAGE_BLOB_CONTAINER_NAME;

    // Best practice: create time limits
    const TEN_MINUTES = 10 * 60 * 1000;
    const NOW = new Date();

    // Best practice: set start time a little before current time to 
    // make sure any clock issues are avoided
    const TEN_MINUTES_BEFORE_NOW = new Date(NOW.valueOf() - TEN_MINUTES);
    const TEN_MINUTES_AFTER_NOW = new Date(NOW.valueOf() + TEN_MINUTES);

    // Best practice: use managed identity - DefaultAzureCredential
    const blobServiceClient = new BlobServiceClient(
        `https://${accountName}.blob.core.windows.net`,
        new DefaultAzureCredential()
      );

    // Best practice: delegation key is time-limited  
    // When using a user delegation key, container must already exist 
    const userDelegationKey = await blobServiceClient.getUserDelegationKey(
        TEN_MINUTES_BEFORE_NOW, 
        TEN_MINUTES_AFTER_NOW
    );

    // Need only create/write permission to upload file
    const blobPermissionsForAnonymousUser = "cw"

    // Best practice: SAS options are time-limited
    const sasOptions = {
        blobName,
        containerName,                                           
        permissions: BlobSASPermissions.parse(blobPermissionsForAnonymousUser), 
        protocol: SASProtocol.HttpsAndHttp,
        startsOn: TEN_MINUTES_BEFORE_NOW,
        expiresOn: TEN_MINUTES_AFTER_NOW
    };
 
    const sasToken = generateBlobSASQueryParameters(
        sasOptions,
        userDelegationKey,
        accountName 
    ).toString();

    return sasToken;
}

Il codice precedente crea un flusso di valori per creare il token di firma di accesso condiviso del contenitore:

Dopo aver creato il token di firma di accesso condiviso del BLOB, è possibile fornirlo al client che lo utilizzerà. Il client può quindi usarlo per caricare un BLOB. Un esempio di codice client illustra come testare la firma di accesso condiviso come consumer.

BLOB: usare il token di firma di accesso condiviso

Dopo aver creato il token di firma di accesso condiviso del BLOB, usare il token. Come esempio di uso del token di firma di accesso condiviso, è possibile:

  • Costruire un URL completo, inclusi il nome del contenitore, il nome del BLOB e la stringa di query. La stringa di query è il token di firma di accesso condiviso.
  • Creare un BlockBlobClient con l'URL del contenitore.
  • Usare il client: in questo esempio caricare BLOB con carica.
// Client or another process uses SAS token to upload content to blob
async function uploadStringToBlob(blobName, sasToken, textAsString){

    // Get environment variables
    const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;
    const containerName = process.env.AZURE_STORAGE_BLOB_CONTAINER_NAME;

    // Create Url SAS token as query string with typical `?` delimiter
    const sasUrl = `https://${accountName}.blob.core.windows.net/${containerName}/${blobName}?${sasToken}`;
    console.log(`\nBlobUrl = ${sasUrl}\n`);

    // Create blob client from SAS token url
    const blockBlobClient = new BlockBlobClient(sasUrl);

    // Upload string
    await blockBlobClient.upload(textAsString, textAsString.length, undefined);    
}

Vedi anche