Condividi tramite


Esercitazione: Caricare un'immagine in un BLOB di Archiviazione di Azure con TypeScript

Questa esercitazione illustra come caricare file da un browser direttamente in Archiviazione BLOB di Azure senza esporre le credenziali. Si utilizzerà TypeScript per implementare il modello Valet Key con token SAS (Shared Access Signature) e identità gestite per un'autenticazione sicura senza l'uso di chiavi.

L'applicazione di esempio include:

  • API di Fastify che genera token SAS a tempo limitato
  • Front-end React che carica i file direttamente in Archiviazione di Azure
  • Infrastruttura come codice per la distribuzione con l'interfaccia della riga di comando per sviluppatori di Azure

Al termine di questa esercitazione si avrà un'applicazione funzionante distribuita in App Azure Container che illustra i caricamenti sicuri dei file senza esporre le credenziali di archiviazione al browser.

Prerequisiti

Prima di iniziare, assicurarsi di disporre di:

Mancia

Questa esercitazione usa GitHub Codespaces, che fornisce un ambiente di sviluppo preconfigurato nel browser. Non è necessaria alcuna configurazione locale.

Architecture

Il front-end richiede un token SAS dall'API, quindi carica i file direttamente su Azure Storage. Dopo il caricamento, l'API elenca tutti i file caricati con token SAS di sola lettura per il loro display.

Screenshot di un'app Web denominata

Concetti chiave

Token di firma di accesso condiviso per delega utente

L'applicazione utilizza i token SAS di delega utente per un'autenticazione sicura senza chiavi. Questi token vengono firmati con le credenziali di Microsoft Entra ID tramite l'identità gestita. L'API genera token di breve durata (10-60 minuti) con autorizzazioni specifiche (lettura, scrittura o eliminazione), consentendo al browser di caricare i file direttamente nella risorsa di archiviazione senza esporre le credenziali.

Distribuzione dell'interfaccia della riga di comando per sviluppatori di Azure

Distribuire l'infrastruttura completa con azd up. Questa procedura crea App contenitore di Azure per il frontend React e il backend API Fastify, configura le identità gestite e assegna le autorizzazioni di controllo degli accessi in base al ruolo (RBAC). L'infrastruttura usa modelli Bicep che seguono i principi di Azure Well-Architected Framework con i moduli verificati di Azure, se applicabile.

Ambiente di sviluppo in container

Il codice di esempio completo di questo tutorial utilizza un contenitore di sviluppo in GitHub Codespaces o in locale con Visual Studio Code.

Annotazioni

È anche possibile eseguire questa esercitazione in locale in Visual Studio Code con l'estensione Dev Containers. Il codice di esempio completo include la configurazione del contenitore di sviluppo.

Aprire l'esempio in GitHub Codespaces

GitHub Codespaces fornisce un ambiente VS Code basato su browser con tutte le dipendenze preinstallate.

Importante

Tutti gli account GitHub possono usare Codespaces con ore gratuite ogni mese. Per ulteriori informazioni, vedere GitHub Codespaces archiviazione e ore centrali inclusi mensilmente.

  1. In un browser web, aprire il repository di esempio e selezionare Code>Crea uno spazio di codice su 'main'.

    Screenshot della pagina del repository GitHub che mostra il pulsante Vai al file, Aggiungi file e codice verde evidenziato.

  2. Attendere l'avvio del contenitore di sviluppo. Questo processo di avvio può richiedere alcuni minuti. I passaggi rimanenti di questa esercitazione si svolgono nel contesto di questo contenitore di sviluppo.

Distribuire l'esempio

  1. Accedere ad Azure.

    azd auth login
    
  2. Effettuare il provisioning delle risorse e distribuire l'esempio nell'ambiente di hosting.

    azd up
    

    Quando richiesto, immettere le informazioni seguenti:

    Sollecito Entrare
    Immettere un nome di ambiente univoco secure-upload
    Selezionare una sottoscrizione di Azure da usare Selezionare la sottoscrizione dall'elenco
    Immettere un valore per il parametro dell'infrastruttura "location" Selezionare le posizioni disponibili

    In alternativa, se si desidera visualizzare le risorse per cui è stato effettuato il provisioning ed esaminare l'output della distribuzione, è possibile eseguire il seguente comando per distribuire senza richieste:

    azd provision
    

    Eseguire quindi questo comando per distribuire il codice dell'applicazione:

    azd deploy
    

    Se si modifica il codice dell'API o dell'app Web, è possibile ridistribuire solo il codice dell'applicazione con uno dei comandi seguenti:

    azd deploy app
    azd deploy api
    
  3. Al termine della distribuzione, prendere nota dell'URL dell'app Web distribuita visualizzata nel terminale.

      (✓) Done: Deploying service app
      - Endpoint: https://app-gp2pofajnjhy6.calmtree-87e53015.eastus2.azurecontainerapps.io/
    

    Si tratta di un URL di esempio. L'URL sarà diverso.

Provare l’esempio

  1. Aprire l'app Web distribuita in una nuova scheda del browser e selezionare un file PNG da caricare. Nella cartella ./docs/media sono disponibili diversi file PNG.

    Screenshot dell'app Web per il caricamento di file in Archiviazione di Azure, che mostra il pulsante Seleziona file e il caricamento del nome del contenitore.

  2. Selezionare Ottieni token SAS, quindi selezionare Carica file.

  3. Visualizza il tuo file caricato nella galleria sotto il pulsante di caricamento.

    Screenshot dell'applicazione web dopo il caricamento di daisies.jpg in Azure Storage, che mostra il nome file, l'URL SAS (firma di accesso condiviso), lo stato di caricamento e l'anteprima dell'immagine.

Cos'è successo?

  • Il file è stato caricato direttamente dal browser in Azure Storage usando un token SAS (Shared Access Signature) di sola scrittura limitato nel tempo.
  • Le immagini della raccolta vengono caricate direttamente da Archiviazione Azure usando token di accesso condiviso (SAS) di sola lettura.
  • Nessun segreto di autenticazione è stato esposto nel browser

Funzionamento del codice

Dopo aver visto l'applicazione in azione, esaminare il modo in cui il codice implementa caricamenti di file sicuri. L'applicazione ha due parti principali:

  1. Back-end API - esegue l'autenticazione con Azure e genera token SAS
  2. Front-end React - carica i file direttamente su Archiviazione di Azure usando token SAS

Le sezioni seguenti illustrano le implementazioni principali del codice.

Server API per generare token SAS ed elencare i file

Il server API esegue l'autenticazione in Archiviazione di Azure e genera token di firma di accesso condiviso con tempo limitato per l'uso del browser.

Autenticazione con identità gestita

L'applicazione usa chiavi di delega utente con identità gestita per l'autenticazione, ovvero l'approccio più sicuro per le applicazioni Azure. ChainedTokenCredential prova i metodi di autenticazione in questo ordine:

  1. In Azure: ManagedIdentityCredential (identità delle app contenitore)
  2. Sviluppo locale: AzureCliCredential (la tua sessione az login)
// From: packages/api/src/lib/azure-storage.ts
export function getCredential(): ChainedTokenCredential {
  if (!_credential) {
    const clientId = process.env.AZURE_CLIENT_ID;
    
    // Create credential chain with ManagedIdentity first
    const credentials = [
      new ManagedIdentityCredential(clientId ? { clientId } : undefined),
      new AzureCliCredential()
    ];
    
    _credential = new ChainedTokenCredential(...credentials);
  }
  return _credential;
}

Dopo l'autenticazione, creare un BlobServiceClient oggetto per interagire con Archiviazione di Azure:

// From: packages/api/src/lib/azure-storage.ts
export function getBlobServiceClient(accountName: string): BlobServiceClient {
  const credential = getCredential();
  const url = `https://${accountName}.blob.core.windows.net`;
  
  return new BlobServiceClient(url, credential);
}

Generare token SAS con chiavi di delega utente

I token di firma di accesso condiviso richiedono una chiave di delega utente, che autentica il token usando le credenziali dell'ID di Microsoft Entra anziché le chiavi dell'account di archiviazione. La chiave è valida per un intervallo di tempo specifico:

const startsOn = new Date();
const expiresOn = new Date(startsOn.valueOf() + minutes * 60 * 1000);

const userDelegationKey = await blobServiceClient.getUserDelegationKey(
  startsOn,
  expiresOn
);

Generare token SAS di sola scrittura per i caricamenti di file

Per i caricamenti di file, l'API genera token di sola scrittura che non possono leggere o eliminare dati. I token scadono dopo 10 minuti:

// From: packages/api/src/routes/sas.ts
const DEFAULT_SAS_TOKEN_PERMISSION = 'w';
const DEFAULT_SAS_TOKEN_EXPIRATION_MINUTES = 10;

const sasToken = generateBlobSASQueryParameters(
  {
    containerName: container,
    blobName: file,
    permissions: BlobSASPermissions.parse(permission),
    startsOn,
    expiresOn
  },
  userDelegationKey,
  accountName
).toString();

const sasUrl = `${blobClient.url}?${sasToken}`;

Livelli di autorizzazione disponibili:

  • 'r' - Lettura (download/visualizzazione)
  • 'w' - Scrittura (caricamento/sovrascrittura) - Usato per i caricamenti
  • 'd' -Elimina
  • 'c' -Creare
  • 'a' - Aggiunta (BLOB di accodamento)

Generare token SAS di sola lettura per elencare e visualizzare i file

Per elencare e visualizzare i file, l'API genera token di sola lettura che scadono dopo 60 minuti:

// From: packages/api/src/routes/list.ts
const LIST_SAS_TOKEN_PERMISSION = 'r';
const LIST_SAS_TOKEN_EXPIRATION_MINUTES = 60;

const sasToken = generateBlobSASQueryParameters(
  {
    containerName: container,
    blobName: blob.name,
    permissions: BlobSASPermissions.parse(LIST_SAS_TOKEN_PERMISSION),
    startsOn,
    expiresOn
  },
  userDelegationKey,
  accountName
).toString();

const sasUrl = `${blobClient.url}?${sasToken}`;

Il client dell'app Web richiede e riceve token SAS dal server API.

Il front-end React richiede token SAS dall'API e li usa per caricare direttamente i file in Azure Storage dal browser.

Il front-end segue un processo in tre passaggi:

  1. Richiedere un token SAS dall'API per un file specifico
  2. Carica direttamente in Archiviazione di Azure usando l'URL del token SAS (firma di accesso condiviso)
  3. Recuperare e visualizzare l'elenco dei file caricati con token SAS di sola lettura

Questa architettura mantiene il back-end leggero: genera solo token, non gestisce mai i dati dei file.

Richiedere un token SAS dell'Archiviazione Blob dal server API

Quando un utente seleziona un file e fa clic su "Get SAS Token", il frontend richiede un token di accesso condiviso di sola scrittura dall'API:

// From: packages/app/src/App.tsx
const handleFileSasToken = () => {
  const permission = 'w'; // write-only
  const timerange = 10;   // 10 minutes expiration

  if (!selectedFile) return;

  // Build API request URL
  const url = `${API_URL}/api/sas?file=${encodeURIComponent(
    selectedFile.name
  )}&permission=${permission}&container=${containerName}&timerange=${timerange}`;

  fetch(url, {
    method: 'GET',
    headers: {
      'Content-Type': 'application/json'
    }
  })
    .then((response) => {
      if (!response.ok) {
        throw new Error(`Error: ${response.status} ${response.statusText}`);
      }
      return response.json();
    })
    .then((data: SasResponse) => {
      const { url } = data;
      setSasTokenUrl(url); // Store the SAS URL for upload
    });
};

Che succede:

  • Invio frontend: GET /api/sas?file=photo.jpg&permission=w&container=upload&timerange=10
  • L'API restituisce: { url: "https://storageaccount.blob.core.windows.net/upload/photo.jpg?sv=2024-05-04&..." }
  • Questo URL è valido per 10 minuti e concede l'accesso in sola scrittura a tale BLOB specifico

Caricare direttamente su Blob Storage utilizzando il token SAS (firma di accesso condiviso)

Dopo aver ricevuto l'URL del token SAS, il front-end converte il file in ArrayBuffer e carica il file direttamente in Azure Storage, ignorando completamente l'API. Ciò riduce il carico del server e migliora le prestazioni.

Convertire il file in arrayBuffer.

// From: packages/app/src/lib/convert-file-to-arraybuffer.ts
export function convertFileToArrayBuffer(file: File): Promise<ArrayBuffer | null> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();

    reader.onload = () => {
      const arrayBuffer = reader.result;
      resolve(arrayBuffer as ArrayBuffer);
    };

    reader.onerror = () => {
      reject(new Error('Error reading file.'));
    };

    reader.readAsArrayBuffer(file);
  });
}

Usa quindi BlockBlobClient da @azure/storage-blob per caricare i dati del file usando l'URL del token SAS.

// From: packages/app/src/App.tsx
const handleFileUpload = () => {
  console.log('SAS Token URL:', sasTokenUrl);

  // Convert file to ArrayBuffer
  convertFileToArrayBuffer(selectedFile as File)
    .then((fileArrayBuffer) => {
      if (fileArrayBuffer === null || fileArrayBuffer.byteLength < 1) {
        throw new Error('Failed to convert file to ArrayBuffer');
      }

      // Create Azure Storage client with SAS URL
      const blockBlobClient = new BlockBlobClient(sasTokenUrl);
      
      // Upload directly to Azure Storage
      return blockBlobClient.uploadData(fileArrayBuffer);
    })
    .then((uploadResponse) => {
      if (!uploadResponse) {
        throw new Error('Upload failed - no response from Azure Storage');
      }
      setUploadStatus('Successfully finished upload');
      
      // After upload, fetch the updated list of files
      const listUrl = `${API_URL}/api/list?container=${containerName}`;
      return fetch(listUrl);
    });
};

Punti principali:

  • Il file non passa mai attraverso il server API
  • Il caricamento passa direttamente dal browser ad Archiviazione di Azure
  • Il token SAS autentica la richiesta.
  • Nessun costo di elaborazione o larghezza di banda del server per la gestione dei file

Recuperare il file direttamente da Archiviazione di Azure e visualizzare l'immagine di anteprima

Dopo un caricamento riuscito, il front-end recupera un elenco di tutti i file nel contenitore. Ogni file nell'elenco include un proprio SAS token di sola lettura:

// From: packages/app/src/App.tsx
const listUrl = `${API_URL}/api/list?container=${containerName}`;

fetch(listUrl)
  .then((response) => {
    if (!response.ok) {
      throw new Error(`Error: ${response.status}`);
    }
    return response.json();
  })
  .then((data: ListResponse) => {
    setList(data.list); // Array of SAS URLs with read permission
  });

Esempio di risposta:

{
  "list": [
    "https://storageaccount.blob.core.windows.net/upload/photo1.jpg?sv=2024-05-04&se=2025-12-18T15:30:00Z&sr=b&sp=r&...",
    "https://storageaccount.blob.core.windows.net/upload/photo2.jpg?sv=2024-05-04&se=2025-12-18T15:30:00Z&sr=b&sp=r&..."
  ]
}

Il front-end utilizza gli URL SAS direttamente nei tag di immagine. Il browser recupera immagini da Archiviazione di Azure usando i token di sola lettura incorporati:

// From: packages/app/src/App.tsx
<Grid container spacing={2}>
  {list.map((item) => {
    const urlWithoutQuery = item.split('?')[0];
    const filename = urlWithoutQuery.split('/').pop() || '';
    const isImage = filename.endsWith('.jpg') || 
                    filename.endsWith('.png') || 
                    filename.endsWith('.jpeg');
    
    return (
      <Grid item xs={6} sm={4} md={3} key={item}>
        <Card>
          {isImage ? (
            <CardMedia component="img" image={item} alt={filename} />
          ) : (
            <Typography>{filename}</Typography>
          )}
        </Card>
      </Grid>
    );
  })}
</Grid>

Funzionamento:

  • Ogni URL nell'elenco include un token SAS in modalità sola lettura (sp=r)
  • Browser effettua richieste GET direttamente ad Azure Storage
  • Nessuna autenticazione necessaria: il token si trova nell'URL
  • I token scadono dopo 60 minuti (configurati nell'API)

Pulire le risorse

Al termine di questa esercitazione, rimuovere tutte le risorse di Azure per evitare addebiti in corso:

azd down

Risoluzione dei problemi

Segnalare problemi con questo esempio nel repository GitHub. Allegare i seguenti elementi al problema.

  • URL dell'articolo
  • Il passaggio o il contesto all'interno dell'articolo che è stato problematico
  • Ambiente di sviluppo

Codice di esempio

Passaggi successivi

Dopo aver appreso come caricare in modo sicuro i file in Archiviazione di Azure, esplorare questi argomenti correlati: