Sdílet prostřednictvím


Kurz: Nahrání obrázku do objektu blob služby Azure Storage pomocí TypeScriptu

V tomto kurzu se dozvíte, jak nahrát soubory z prohlížeče přímo do služby Azure Blob Storage bez vystavení přihlašovacích údajů. K implementaci vzoru klíče Valet s tokeny sdíleného přístupového podpisu (SAS) a spravované identity použijete TypeScript pro zabezpečené ověřování bez klíčů.

Ukázková aplikace zahrnuje:

  • Rozhraní API Fastify, které generuje tokeny SAS s časovým omezením
  • Front-end Reactu, který nahrává soubory přímo do Azure Storage
  • Infrastruktura jako kód pro nasazení pomocí Azure Developer CLI

Na konci tohoto kurzu budete mít nasazenou funkční aplikaci do Azure Container Apps, která demonstruje zabezpečené nahrávání souborů bez vystavení přihlašovacích údajů k úložišti v prohlížeči.

Požadavky

Než začnete, ujistěte se, že máte:

Spropitné

V tomto kurzu se používá GitHub Codespaces, které poskytuje předem nakonfigurované vývojové prostředí ve vašem prohlížeči. Nevyžaduje se žádné místní nastavení.

Architecture

Diagram architektury Azure znázorňující tok nahrávání: Uživatel vybere soubor ve front-endu webové aplikace, front-end žádá o token SAS z back-endu aplikace API, back-end získá klíč delegování uživatele ze spravované identity (Managed Identity) a vygeneruje token SAS z kontejneru objektů blob služby Storage, front-end nahraje soubor přímo do služby Storage pomocí tokenu SAS, back-end dotazuje Storage, aby vypsal nahrané soubory. Container Registry poskytuje image kontejnerů pro obě aplikace.

Front-end požaduje token SAS z rozhraní API a pak nahraje soubory přímo do Služby Azure Storage. Po nahrání rozhraní API zobrazí seznam všech nahraných souborů s tokeny SAS jen pro čtení pro zobrazení.

Snímek obrazovky webové aplikace s názvem Nahrát soubor do služby Azure Storage s tlačítkem Vybrat soubor a zobrazeným názvem kontejneru

Klíčové koncepty

Delegované SAS tokeny uživatele

Aplikace používá tokeny SAS delegování uživatele k zabezpečenému ověřování bez klíčů. Tyto tokeny jsou podepsané pomocí přihlašovacích údajů Microsoft Entra ID prostřednictvím spravované identity. Rozhraní API generuje krátkodobé tokeny (10 až 60 minut) s konkrétními oprávněními (čtení, zápis nebo odstranění), což prohlížeči umožňuje nahrávat soubory přímo do úložiště bez vystavení přihlašovacích údajů.

Nasazení Azure Developer CLI

Nasaďte kompletní infrastrukturu pomocí nástroje azd up. Tím se zřídí Služba Azure Container Apps pro front-end React a back-end rozhraní API Fastify, nakonfiguruje spravované identity a přiřadí oprávnění RBAC. Infrastruktura používá šablony Bicep podle principů architektury Azure Well-Architected s využitím ověřených modulů Azure, pokud je to možné.

Vývojové prostředí kontejneru

Kompletní ukázkový kód tohoto kurzu používá vývojový kontejner buď v GitHub Codespaces, nebo v místním editoru Visual Studio Code.

Poznámka:

Tento kurz můžete spustit také místně v editoru Visual Studio Code s rozšířením Dev Containers. Kompletní ukázkový kód zahrnuje konfiguraci vývojového kontejneru.

Otevření ukázky v GitHub Codespaces

GitHub Codespaces poskytuje prostředí VS Code založené na prohlížeči se všemi předinstalovanými závislostmi.

Důležitý

Všechny účty GitHubu můžou každý měsíc používat Codespaces s volnými hodinami. Podrobnější informace najdete v GitHub Codespaces o měsíčně zahrnutém úložišti a hodinách jádra.

  1. Ve webovém prohlížeči otevřete ukázkové úložiště a v hlavním okně vyberte Code>Create codespace.

    Snímek obrazovky se stránkou úložiště GitHub se zvýrazněným tlačítkem Přejít na soubor, Přidat soubor a zelené tlačítko Kód

  2. Počkejte, až se spustí vývojový kontejner. Tento proces spuštění může trvat několik minut. Zbývající kroky v tomto kurzu probíhají v kontextu tohoto vývojového kontejneru.

Nasazení ukázky

  1. Přihlaste se k Azure.

    azd auth login
    
  2. Zřiďte prostředky a nasaďte ukázku do hostitelského prostředí.

    azd up
    

    Po zobrazení výzvy zadejte následující informace:

    Výzva Vstoupit
    Zadejte jedinečný název prostředí. secure-upload
    Vyberte předplatné Azure, které chcete použít. V seznamu vyberte své předplatné.
    Zadejte hodnotu parametru infrastruktury 'location'. Výběr z dostupných umístění

    Pokud chcete vidět, jaké prostředky byly zřízeny a jaký byl výsledek nasazení, můžete spustit následující příkaz k provedení nasazení bez výzev:

    azd provision
    

    Pak spuštěním tohoto příkazu nasaďte kód aplikace:

    azd deploy
    

    Pokud změníte kód rozhraní API nebo webové aplikace, můžete znovu nasadit pouze kód aplikace pomocí jednoho z následujících příkazů:

    azd deploy app
    azd deploy api
    
  3. Po dokončení nasazení si poznamenejte adresu URL nasazené webové aplikace zobrazené v terminálu.

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

    Toto je příklad adresy URL. Vaše adresa URL se bude lišit.

Vyzkoušejte ukázku.

  1. Otevřete nasazenou webovou aplikaci na nové kartě prohlížeče a vyberte soubor PNG, který chcete nahrát. Několik souborů PNG je k dispozici ve složce ./docs/media.

    Snímek obrazovky webové aplikace pro nahrání souborů do Služby Azure Storage se zobrazeným tlačítkem Vybrat soubor a nahrání názvu kontejneru

  2. Vyberte Získat token SAS a pak vyberte Nahrát soubor.

  3. Prohlédněte si nahraný soubor v galerii pod tlačítkem pro nahrání.

    Snímek obrazovky webové aplikace po nahrání daisies.jpg do Služby Azure Storage se zobrazeným názvem souboru, adresou URL SAS, stavem nahrání a miniaturou obrázku

Co se právě stalo?

  • Váš soubor nahraný přímo z prohlížeče do Služby Azure Storage pomocí časově omezeného tokenu SAS jen pro zápis
  • Obrázky v galerii se načítají přímo ze služby Azure Storage pomocí tokenů SAS jen pro čtení.
  • V prohlížeči nebyly vystaveny žádné tajné kódy ověřování.

Jak kód funguje

Teď, když jste viděli aplikaci v akci, prozkoumejte, jak kód implementuje zabezpečené nahrávání souborů. Aplikace má dvě hlavní části:

  1. Back-end rozhraní API – Ověřuje se v Azure a generuje tokeny SAS.
  2. Front-end React – Nahraje soubory přímo do služby Azure Storage pomocí tokenů SAS.

Následující části projdou klíčovými implementacemi kódu.

Server rozhraní API pro generování tokenů SAS a výpis souborů

Server rozhraní API se ověří ve službě Azure Storage a vygeneruje časově omezené tokeny SAS pro použití prohlížeče.

Ověřování pomocí spravované identity

Aplikace používá klíče delegování uživatelů se spravovanou identitou k ověřování, což je nejbezpečnější přístup pro aplikace Azure. ChainedTokenCredential zkouší metody ověřování v tomto pořadí:

  1. V Azure: ManagedIdentityCredential (identita Container Apps)
  2. Místní vývoj: AzureCliCredential (vaše az login relace)
// 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;
}

Po ověření vytvořte BlobServiceClient pro interakci se službou Azure Storage:

// 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);
}

Generování tokenů SAS pomocí klíčů delegování uživatele

Tokeny SAS vyžadují klíč delegování uživatele, který token ověřuje pomocí přihlašovacích údajů Microsoft Entra ID místo klíčů účtu úložiště. Klíč je platný pro konkrétní časový rozsah:

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

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

Generování tokenů SAS jen pro zápis pro nahrávání souborů

Pro nahrání souborů rozhraní API generuje tokeny jen pro zápis, které nemůžou číst ani odstraňovat data. Platnost tokenů vyprší po 10 minutách:

// 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}`;

Dostupné úrovně oprávnění:

  • 'r' - Číst (stáhnout/zobrazit)
  • 'w' - Zápis (nahrávání/přepsání) – používá se pro nahrávání.
  • 'd' -Odstranit
  • 'c' -Vytvořit
  • 'a' – Přidat (přídatelné objekty blob)

Generování tokenů SAS jen pro čtení pro výpis a zobrazení souborů

Pro výpis a zobrazení souborů rozhraní API generuje tokeny jen pro čtení, jejichž platnost vyprší po 60 minutách:

// 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}`;

Požadavek klienta webové aplikace a příjem tokenů SAS ze serveru rozhraní API

Front-end react požaduje tokeny SAS z rozhraní API a používá je k přímému nahrání souborů do Služby Azure Storage z prohlížeče.

Front-end se řídí třemi kroky:

  1. Vyžádání tokenu SAS z rozhraní API pro konkrétní soubor
  2. Nahrání přímo do Azure Storage pomocí adresy URL tokenu SAS
  3. Načtení a zobrazení seznamu nahraných souborů s tokeny SAS jen pro čtení

Tato architektura udržuje back-end jednoduchý – generuje pouze tokeny, nikdy nezpracuje data souboru.

Vyžádání tokenu SAS služby Blob Storage ze serveru rozhraní API

Když uživatel vybere soubor a klikne na Získat token SAS, front-end požádá o token SAS jen pro zápis z rozhraní 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
    });
};

Co se stane:

  • Front-end odesílá: GET /api/sas?file=photo.jpg&permission=w&container=upload&timerange=10
  • Vrátí rozhraní API: { url: "https://storageaccount.blob.core.windows.net/upload/photo.jpg?sv=2024-05-04&..." }
  • Tato adresa URL je platná 10 minut a uděluje přístup pouze pro zápis k tomuto konkrétnímu objektu blob.

Nahrání přímo do služby Blob Storage pomocí tokenu SAS

Po přijetí adresy URL tokenu SAS front-end soubor převede na ArrayBuffer a soubor nahraje přímo do Azure Storage – zcela vynechá rozhraní API. Tím se snižuje zatížení serveru a zvyšuje se výkon.

Převeďte soubor na 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);
  });
}

Potom pomocí BlockBlobClient z @azure/storage-blob nahrajte data souboru pomocí adresy URL tokenu 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);
    });
};

klíčové body:

  • Soubor nikdy neprochází přes váš server rozhraní API.
  • Nahrání přejde přímo z prohlížeče do Azure Storage.
  • Token SAS ověřuje požadavek.
  • Žádné náklady na šířku pásma serveru ani na zpracování souborů

Načtení souboru přímo ze služby Azure Storage a zobrazení miniatury

Po úspěšném nahrání front-end načte seznam všech souborů v kontejneru. Každý soubor v seznamu má vlastní token SAS jen pro čtení:

// 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
  });

Příklad odpovědi:

{
  "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&..."
  ]
}

Front-end používá adresy URL SAS přímo ve značkách obrázků. Prohlížeč načte obrázky ze služby Azure Storage pomocí vložených tokenů jen pro čtení:

// 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>

Jak to funguje:

  • Každá adresa URL v seznamu obsahuje token SAS jen pro čtení (sp=r).
  • Prohlížeč provádí požadavky GET přímo do Azure Storage.
  • Nevyžaduje se žádné ověřování – token je v adrese URL.
  • Platnost tokenů vyprší po 60 minutách (nakonfigurovaných v rozhraní API)

Vyčištění prostředků

Až tento kurz dokončíte, odeberte všechny prostředky Azure, abyste se vyhnuli průběžným poplatkům:

azd down

Řešení problémů

Nahlašte problémy s touto ukázkou v úložišti GitHub. Uveďte následující informace o problému:

  • Adresa URL článku
  • Krok nebo kontext v článku, který byl problematický
  • Vaše vývojové prostředí

Ukázkový kód

Další kroky

Teď, když jste se dozvěděli, jak bezpečně nahrát soubory do Služby Azure Storage, projděte si tato související témata: