En este artículo se muestra cómo conectarse a Azure Blob Storage mediante la biblioteca cliente de Azure Blob Storage para JavaScript. Una vez conectado, el código puede funcionar en contenedores, blobs y características del servicio Blob Storage.
Abra un símbolo del sistema y cambie a la carpeta del proyecto. Cambie YOUR-DIRECTORY al nombre de la carpeta:
cd YOUR-DIRECTORY
Si aún no tiene un archivo package.json en el directorio, inicialice el proyecto para crearlo:
npm init -y
Instale TypeScript y la biblioteca cliente de Azure Blob Storage para JavaScript con tipos TypeScript incluidos:
npm install typescript @azure/storage-blob
Si quiere usar conexiones sin contraseña mediante Microsoft Entra ID, instale la biblioteca cliente de Azure Identity para JavaScript:
npm install @azure/identity
Autorización del acceso y conexión a Blob Storage
Microsoft Entra ID proporciona la conexión más segura mediante la administración de la identidad de conexión (identidad administrada). Esta funcionalidad sin contraseña permite desarrollar una aplicación que no requiere tener secretos (claves o cadenas de conexión) almacenados en el código.
Configuración del acceso de identidad a la nube de Azure
Para conectarse a Azure sin contraseñas, debe configurar una identidad de Azure o usar una identidad existente. Una vez configurada la identidad, asegúrese de asignar los roles adecuados a la identidad.
Para llevar a cabo la autorización de acceso sin contraseña con Microsoft Entra ID, deberá usar una credencial de Azure. El tipo de credencial que necesita depende de dónde se ejecute la aplicación. Use esta tabla como guía.
Configuración de roles de cuenta de almacenamiento
El recurso de Storage debe tener uno o varios de los siguientes roles de Azure RBAC asignados al recurso de identidad con el que planea conectarse. Configure los roles de Azure Storage para cada identidad que creó en el paso anterior: nube de Azure y desarrollo local.
Después de completar la configuración, cada identidad necesita al menos uno de los roles adecuados:
Una vez configurados los roles de identidad de la cuenta de almacenamiento de Azure y el entorno local, cree un archivo TypeScript que incluya el paquete @azure/identity. Cree una credencial, como DefaultAzureCredential, para implementar conexiones sin contraseña en Blob Storage. Use esa credencial para autenticarse con un objeto BlobServiceClient.
// connect-with-default-azure-credential.js
// You must set up RBAC for your identity with one of the following roles:
// - Storage Blob Data Reader
// - Storage Blob Data Contributor
import { DefaultAzureCredential } from '@azure/identity';
import { BlobServiceClient } from '@azure/storage-blob';
import * as dotenv from 'dotenv';
dotenv.config();
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME as string;
if (!accountName) throw Error('Azure Storage accountName not found');
const blobServiceClient = new BlobServiceClient(
`https://${accountName}.blob.core.windows.net`,
new DefaultAzureCredential()
);
async function main() {
const containerName = 'my-container';
const blobName = 'my-blob';
const timestamp = Date.now();
const fileName = `my-new-file-${timestamp}.txt`;
// create container client
const containerClient = await blobServiceClient.getContainerClient(
containerName
);
// create blob client
const blobClient = await containerClient.getBlockBlobClient(blobName);
// download file
const downloadResult = await blobClient.downloadToFile(fileName);
if (downloadResult.errorCode) throw Error(downloadResult.errorCode);
console.log(
`${fileName} downloaded ${downloadResult.contentType}, isCurrentVersion: ${downloadResult.isCurrentVersion}`
);
}
main()
.then(() => console.log(`success`))
.catch((err: unknown) => {
if (err instanceof Error) {
console.log(err.message);
}
});
El paquete dotenv se usa para leer el nombre de la cuenta de almacenamiento de un archivo .env. No hace falta comprobar este archivo en el control de código fuente. Si usa una entidad de servicio local como parte de la configuración de DefaultAzureCredential, cualquier información de seguridad de esa credencial también entrará en el archivo .env.
Si tiene previsto implementar la aplicación en servidores y clientes que se ejecutan fuera de Azure, cree una de las credenciales que satisfagan sus necesidades.
Cree una StorageSharedKeyCredential a partir del nombre de la cuenta de almacenamiento y la clave de la cuenta. A continuación, pase StorageSharedKeyCredential al constructor de clase BlobServiceClient para crear un cliente.
// connect-with-account-name-and-key.js
import {
BlobServiceClient,
StorageSharedKeyCredential
} from '@azure/storage-blob';
import * as dotenv from 'dotenv';
import path from 'path';
dotenv.config();
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME as string;
const accountKey = process.env.AZURE_STORAGE_ACCOUNT_KEY as string;
if (!accountName) throw Error('Azure Storage accountName not found');
if (!accountKey) throw Error('Azure Storage accountKey not found');
const sharedKeyCredential = new StorageSharedKeyCredential(
accountName,
accountKey
);
const blobServiceClient = new BlobServiceClient(
`https://${accountName}.blob.core.windows.net`,
sharedKeyCredential
);
async function main(): Promise<void> {
const containerName = 'my-container';
const blobName = 'my-blob';
const timestamp = Date.now();
const fileName = path.join(
__dirname,
'../files',
`my-new-file-${timestamp}.txt`
);
// create container client
const containerClient = await blobServiceClient.getContainerClient(
containerName
);
// create blob client
const blobClient = await containerClient.getBlockBlobClient(blobName);
// download file
const downloadResult = await blobClient.downloadToFile(fileName);
if (downloadResult.errorCode) throw Error(downloadResult.errorCode);
console.log(
`${fileName} downloaded, created on ${downloadResult.createdOn}}`
);
}
main()
.then(() => console.log(`success`))
.catch((err: unknown) => {
if (err instanceof Error) {
console.log(err.message);
}
});
El paquete dotenv se usa para leer el nombre y la clave de la cuenta de almacenamiento de un archivo .env. No hace falta comprobar este archivo en el control de código fuente.
La clave de acceso de la cuenta debe usarse con precaución. Si la clave de acceso de la cuenta se pierde o se coloca por accidente en una ubicación no segura, el servicio puede volverse vulnerable. Cualquier persona que tenga la clave de acceso puede autorizar las solicitudes en la cuenta de almacenamiento y tiene acceso eficaz a todos los datos. DefaultAzureCredential proporciona características y ventajas de seguridad mejoradas y es el enfoque recomendado para administrar la autorización en los servicios de Azure.
Cree un URI al recurso mediante el punto de conexión de Blob service y el token de SAS. A continuación, cree un objeto BlobServiceClient con el URI. El token de SAS es una serie de pares nombre-valor en la cadena de consulta en el formato como:
En función de la herramienta que use para generar el token de SAS, es posible que la cadena de consulta ? ya se haya agregado al token de SAS.
// connect-with-sas-token.js
import { BlobServiceClient } from '@azure/storage-blob';
import * as dotenv from 'dotenv';
dotenv.config();
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;
const sasToken = process.env.AZURE_STORAGE_SAS_TOKEN;
if (!accountName) throw Error('Azure Storage accountName not found');
if (!sasToken) throw Error('Azure Storage accountKey not found');
// https://YOUR-RESOURCE-NAME.blob.core.windows.net?YOUR-SAS-TOKEN
const blobServiceUri = `https://${accountName}.blob.core.windows.net?${sasToken}`;
// SAS tokens do not require an additional credential because
// the token is the credential
const credential = undefined;
const blobServiceClient = new BlobServiceClient(blobServiceUri, credential);
async function main() {
const containerName = 'my-container';
const blobName = 'my-blob';
const timestamp = Date.now();
const fileName = `my-new-file-${timestamp}.txt`;
// create container client
const containerClient = await blobServiceClient.getContainerClient(
containerName
);
// create blob client
const blobClient = await containerClient.getBlockBlobClient(blobName);
// download file
const downloadResult = await blobClient.downloadToFile(fileName);
if (downloadResult.errorCode) throw Error(downloadResult.errorCode);
console.log(
`${fileName} downloaded ${downloadResult.contentType}, isCurrentVersion: ${downloadResult.isCurrentVersion}`
);
}
main()
.then(() => console.log(`success`))
.catch((err: unknown) => {
if (err instanceof Error) {
console.log(err.message);
}
});
El paquete dotenv se usa para leer el nombre y el token de SAS de la cuenta de almacenamiento de un archivo .env. No hace falta comprobar este archivo en el control de código fuente.
Para generar y administrar tokens de SAS, consulte cualquiera de estos artículos:
Para escenarios en los que se utilizan firmas de acceso compartido (SAS), Microsoft recomienda usar un SAS de delegación de usuario. Una SAS de delegación de usuarios está protegida con credenciales de Microsoft Entra en lugar de la clave de cuenta. Para obtener más información, vea Creación de una SAS de delegación de usuarios con JavaScript.
Creación de un objeto ContainerClient
Puede crear el objeto ContainerClient desde BlobServiceClient o directamente.
Creación de un objeto ContainerClient desde BlobServiceClient
Cree el objeto ContainerClient a partir de BlobServiceClient.
// Azure Storage dependency
import {
BlobServiceClient,
StorageSharedKeyCredential
} from '@azure/storage-blob';
// For development environment - include environment variables from .env
import * as dotenv from 'dotenv';
dotenv.config();
// Azure Storage resource name
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME as string;
if (!accountName) throw Error('Azure Storage accountName not found');
// Azure Storage resource key
const accountKey = process.env.AZURE_STORAGE_ACCOUNT_KEY as string;
if (!accountKey) throw Error('Azure Storage accountKey not found');
// Create credential
const sharedKeyCredential = new StorageSharedKeyCredential(
accountName,
accountKey
);
const baseUrl = `https://${accountName}.blob.core.windows.net`;
const containerName = `my-container`;
// Create BlobServiceClient
const blobServiceClient = new BlobServiceClient(
`${baseUrl}`,
sharedKeyCredential
);
async function main(): Promise<void> {
try {
// Create container client
const containerClient = await blobServiceClient.getContainerClient(
containerName
);
// do something with containerClient...
let i = 1;
// List blobs in container
for await (const blob of containerClient.listBlobsFlat({
includeMetadata: true,
includeSnapshots: false,
includeTags: true,
includeVersions: false,
prefix: ''
})) {
console.log(`Blob ${i++}: ${blob.name}`);
}
} catch (err) {
console.log(err);
throw err;
}
}
main()
.then(() => console.log(`success`))
.catch((err: unknown) => {
if (err instanceof Error) {
console.log(err.message);
}
});
// Azure Storage dependency
import { ContainerClient } from '@azure/storage-blob';
// Azure authentication for credential dependency
import { DefaultAzureCredential } from '@azure/identity';
// For development environment - include environment variables from .env
import * as dotenv from 'dotenv';
dotenv.config();
// Azure Storage resource name
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME as string;
if (!accountName) throw Error('Azure Storage accountName not found');
// Azure SDK needs base URL
const baseUrl = `https://${accountName}.blob.core.windows.net`;
// Unique container name
const timeStamp = Date.now();
const containerName = `my-container`;
async function main(): Promise<void> {
try {
// create container client from DefaultAzureCredential
const containerClient = new ContainerClient(
`${baseUrl}/${containerName}`,
new DefaultAzureCredential()
);
// do something with containerClient...
let i = 1;
// List blobs in container
for await (const blob of containerClient.listBlobsFlat({
includeMetadata: true,
includeSnapshots: false,
includeTags: true,
includeVersions: false,
prefix: ''
})) {
console.log(`Blob ${i++}: ${blob.name}`);
}
} catch (err) {
console.log(err);
throw err;
}
}
main()
.then(() => console.log(`success`))
.catch((err: unknown) => {
if (err instanceof Error) {
console.log(err.message);
}
});
// Azure Storage dependency
import {
ContainerClient,
StorageSharedKeyCredential
} from '@azure/storage-blob';
// For development environment - include environment variables from .env
import * as dotenv from 'dotenv';
dotenv.config();
// Azure Storage resource name
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME as string;
if (!accountName) throw Error('Azure Storage accountName not found');
// Azure Storage resource key
const accountKey = process.env.AZURE_STORAGE_ACCOUNT_KEY as string;
if (!accountKey) throw Error('Azure Storage accountKey not found');
const sharedKeyCredential = new StorageSharedKeyCredential(
accountName,
accountKey
);
const baseUrl = `https://${accountName}.blob.core.windows.net`;
const containerName = `my-container`;
async function main(): Promise<void> {
try {
// create container from ContainerClient
const containerClient = new ContainerClient(
`${baseUrl}/${containerName}`,
sharedKeyCredential
);
// do something with containerClient...
let i = 1;
// List blobs in container
for await (const blob of containerClient.listBlobsFlat({
includeMetadata: true,
includeSnapshots: false,
includeTags: true,
includeVersions: false,
prefix: ''
})) {
console.log(`Blob ${i++}: ${blob.name}`);
}
} catch (err) {
console.log(err);
throw err;
}
}
main()
.then(() => console.log(`success`))
.catch((err: unknown) => {
if (err instanceof Error) {
console.log(err.message);
}
});
Importante
La clave de acceso de la cuenta debe usarse con precaución. Si la clave de acceso de la cuenta se pierde o se coloca por accidente en una ubicación no segura, el servicio puede volverse vulnerable. Cualquier persona que tenga la clave de acceso puede autorizar las solicitudes en la cuenta de almacenamiento y tiene acceso eficaz a todos los datos. DefaultAzureCredential proporciona características y ventajas de seguridad mejoradas y es el enfoque recomendado para administrar la autorización en los servicios de Azure.
// Azure Storage dependency
import { ContainerClient } from '@azure/storage-blob';
// For development environment - include environment variables
import * as dotenv from 'dotenv';
dotenv.config();
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME as string;
if (!accountName) throw Error('Azure Storage accountName not found');
// Container must exist prior to running this script
const containerName = `my-container`;
// SAS token must have LIST permissions on container that haven't expired
const sasToken = process.env.AZURE_STORAGE_SAS_TOKEN as string;
// Create SAS URL
const sasUrl = `https://${accountName}.blob.core.windows.net/${containerName}?${sasToken}`;
async function main(): Promise<void> {
try {
// create container client from SAS token
const containerClient = new ContainerClient(sasUrl);
// do something with containerClient...
let i = 1;
// List blobs in container
for await (const blob of containerClient.listBlobsFlat({
includeMetadata: true,
includeSnapshots: false,
includeTags: true,
includeVersions: false,
prefix: ''
})) {
console.log(`Blob ${i++}: ${blob.name}`);
}
} catch (err) {
console.log(err);
throw err;
}
}
main()
.then(() => console.log(`success`))
.catch((err: unknown) => {
if (err instanceof Error) {
console.log(err.message);
}
});
Nota:
Para escenarios en los que se utilizan firmas de acceso compartido (SAS), Microsoft recomienda usar un SAS de delegación de usuario. Una SAS de delegación de usuarios está protegida con credenciales de Microsoft Entra en lugar de la clave de cuenta. Para obtener más información, vea Creación de una SAS de delegación de usuarios con JavaScript.
El paquete dotenv se usa para leer el nombre de la cuenta de almacenamiento de un archivo .env. No hace falta comprobar este archivo en el control de código fuente.
Creación de un objeto BlobClient
Puede crear cualquiera de los objetos BlobClient, que se enumeran a continuación, desde un ContainerClient o directamente.
// Azure Storage dependency
import {
BlockBlobClient,
BlockBlobUploadHeaders,
BlockBlobUploadResponse
} from '@azure/storage-blob';
import { getBlockBlobClientFromDefaultAzureCredential } from './auth-get-client';
// For development environment - include environment variables from .env
import * as dotenv from 'dotenv';
dotenv.config();
// Container must exist prior to running this script
const containerName = `my-container`;
// Random blob name and contents
const timeStamp = Date.now();
const blobName = `${timeStamp}-my-blob.txt`;
const fileContentsAsString = 'Hello there.';
const blockBlobClient: BlockBlobClient =
getBlockBlobClientFromDefaultAzureCredential(containerName, blobName);
async function main(
blockBlobClient: BlockBlobClient
): Promise<BlockBlobUploadHeaders> {
// Get file url - available before contents are uploaded
console.log(`blob.url: ${blockBlobClient.url}`);
// Upload file contents
const result: BlockBlobUploadHeaders = await blockBlobClient.upload(
fileContentsAsString,
fileContentsAsString.length
);
if (result.errorCode) throw Error(result.errorCode);
// Get results
return result;
}
main(blockBlobClient)
.then((result) => {
console.log(result);
console.log(`success`);
})
.catch((err: unknown) => {
if (err instanceof Error) {
console.log(err.message);
}
});
/*
Response looks like this:
{
etag: '"0x8DAD247F1F4896E"',
lastModified: 2022-11-29T20:26:07.000Z,
contentMD5: <Buffer 9d 6a 29 63 87 20 77 db 67 4a 27 a3 9c 49 2e 61>,
clientRequestId: 'a07fdd1f-5937-44c7-984f-0699a48a05c0',
requestId: '3580e726-201e-0045-1a30-0474f6000000',
version: '2021-04-10',
date: 2022-11-29T20:26:06.000Z,
isServerEncrypted: true,
'content-length': '0',
server: 'Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0',
'x-ms-content-crc64': 'BLv7vb1ONT8=',
body: undefined
}
*/
// Azure Storage dependency
import {
BlockBlobClient,
BlockBlobUploadHeaders,
BlockBlobUploadResponse,
StorageSharedKeyCredential
} from '@azure/storage-blob';
// For development environment - include environment variables from .env
import * as dotenv from 'dotenv';
dotenv.config();
// Azure Storage resource name
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME as string;
if (!accountName) throw Error('Azure Storage accountName not found');
// Azure Storage resource key
const accountKey = process.env.AZURE_STORAGE_ACCOUNT_KEY as string;
if (!accountKey) throw Error('Azure Storage accountKey not found');
// Create credential
const sharedKeyCredential: StorageSharedKeyCredential =
new StorageSharedKeyCredential(accountName, accountKey);
const baseUrl = `https://${accountName}.blob.core.windows.net`;
const containerName = `my-container`;
const blobName = `my-blob`;
const fileContentsAsString = 'Hello there.';
async function main(): Promise<void> {
try {
// create blob from BlockBlobClient
const blockBlobClient = new BlockBlobClient(
`${baseUrl}/${containerName}/${blobName}`,
sharedKeyCredential
);
// Upload data to the blob
const blockBlobUploadResponse: BlockBlobUploadHeaders =
await blockBlobClient.upload(
fileContentsAsString,
fileContentsAsString.length
);
if (blockBlobUploadResponse.errorCode)
throw Error(blockBlobUploadResponse.errorCode);
console.log(`blob ${blockBlobClient.url} created`);
} catch (err) {
console.log(err);
throw err;
}
}
main()
.then(() => console.log(`success`))
.catch((err: unknown) => {
if (err instanceof Error) {
console.log(err.message);
}
});
Importante
La clave de acceso de la cuenta debe usarse con precaución. Si la clave de acceso de la cuenta se pierde o se coloca por accidente en una ubicación no segura, el servicio puede volverse vulnerable. Cualquier persona que tenga la clave de acceso puede autorizar las solicitudes en la cuenta de almacenamiento y tiene acceso eficaz a todos los datos. DefaultAzureCredential proporciona características y ventajas de seguridad mejoradas y es el enfoque recomendado para administrar la autorización en los servicios de Azure.
/**
* Best practice - use managed identity to avoid keys & connection strings
* managed identity is implemented with @azure/identity's DefaultAzureCredential
*
* The identity that the managed identity chain selects must have the
* correct roles applied in order to work correctly.
*
* For local development: add your personal identity on your resource group
* az role assignment create --assignee "<your-username>" \
* --role "Blob Data Contributor" \
* --resource-group "<your-resource-group-name>"
**/
//const logger = require('@azure/logger');
//logger.setLogLevel('info');
//<Snippet_Dependencies>
import {
BlobSASPermissions,
BlobSASSignatureValues,
BlobServiceClient,
BlockBlobClient,
BlockBlobUploadHeaders,
BlockBlobUploadResponse,
generateBlobSASQueryParameters,
SASProtocol,
SASQueryParameters,
ServiceGetUserDelegationKeyResponse
} from '@azure/storage-blob';
// used for local environment variables
import * as dotenv from 'dotenv';
dotenv.config();
// Get BlobServiceClient
import { getBlobServiceClientFromDefaultAzureCredential } from './auth-get-client';
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME as string;
const blobServiceClient: BlobServiceClient =
getBlobServiceClientFromDefaultAzureCredential();
//</Snippet_Dependencies>
//<Snippet_CreateBlobSas>
// Server creates User Delegation SAS Token for blob
async function createBlobSas(
blobServiceClient: BlobServiceClient,
blobName: string
): Promise<string> {
const containerName = 'my-container';
// 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: delegation key is time-limited
// When using a user delegation key, container must already exist
const userDelegationKey: ServiceGetUserDelegationKeyResponse =
await blobServiceClient.getUserDelegationKey(
TEN_MINUTES_BEFORE_NOW,
TEN_MINUTES_AFTER_NOW
);
if (userDelegationKey.errorCode) throw Error(userDelegationKey.errorCode);
// Need only create/write permission to upload file
const blobPermissionsForAnonymousUser = 'cw';
// Best practice: SAS options are time-limited
const sasOptions: BlobSASSignatureValues = {
blobName,
containerName,
permissions: BlobSASPermissions.parse(blobPermissionsForAnonymousUser),
protocol: SASProtocol.HttpsAndHttp,
startsOn: TEN_MINUTES_BEFORE_NOW,
expiresOn: TEN_MINUTES_AFTER_NOW
};
const sasQueryParameters: SASQueryParameters = generateBlobSASQueryParameters(
sasOptions,
userDelegationKey,
accountName
);
const sasToken: string = sasQueryParameters.toString();
return sasToken;
}
//</Snippet_CreateBlobSas>
//<Snippet_UploadToBlob>
// Client or another process uses SAS token to upload content to blob
async function uploadStringToBlob(
blobName: string,
sasToken,
textAsString: string
): Promise<BlockBlobUploadHeaders> {
// Get environment variables
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME as string;
const containerName = 'my-container';
// 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
const blockBlobUploadResponse: BlockBlobUploadHeaders =
await blockBlobClient.upload(textAsString, textAsString.length, undefined);
if (blockBlobUploadResponse.errorCode)
throw Error(blockBlobUploadResponse.errorCode);
return blockBlobUploadResponse;
}
//</Snippet_UploadToBlob>
//<Snippet_Main>
async function main(blobServiceClient: BlobServiceClient) {
// Create random blob name for text file
const blobName = `${(0 | (Math.random() * 9e6)).toString(36)}.txt`;
// Server creates SAS Token
const userDelegationSasForBlob: string = await createBlobSas(
blobServiceClient,
blobName
);
// Server hands off SAS Token & blobName to client to
// Upload content
const result: BlockBlobUploadHeaders = await uploadStringToBlob(
blobName,
userDelegationSasForBlob,
'Hello Blob World'
);
if (result.errorCode) throw Error(result.errorCode);
console.log(`\n${blobName} uploaded successfully ${result.lastModified}\n`);
}
main(blobServiceClient)
.then(() => {
console.log(`success`);
})
.catch((err: unknown) => {
if (err instanceof Error) {
console.log(err.message);
}
});
//</Snippet_Main>
Nota:
Para escenarios en los que se utilizan firmas de acceso compartido (SAS), Microsoft recomienda usar un SAS de delegación de usuario. Una SAS de delegación de usuarios está protegida con credenciales de Microsoft Entra en lugar de la clave de cuenta. Para obtener más información, vea Creación de una SAS de delegación de usuarios con JavaScript.
El paquete dotenv se usa para leer el nombre de la cuenta de almacenamiento de un archivo .env. No hace falta comprobar este archivo en el control de código fuente.