← Tous les guidesStockage et diffusion

Téléchargements privés sur DigitalOcean Spaces avec liens temporaires

Créez des téléchargements privés sur DigitalOcean Spaces avec Next.js. Vérifiez le propriétaire, signez des liens temporaires et testez les accès refusés.

Aller aux étapesDépôt GitHub compagnonCompanion Next.js project and READMETylorMayfield/spaces-private-downloadsVoir sur GitHub

Le piège du bouton réservé aux membres

Un client se connecte, clique sur Télécharger et reçoit son rapport. Les téléchargements privés sur DigitalOcean Spaces permettent ce fonctionnement sans faire passer tout le fichier par votre serveur Next.js. Gardez l'objet privé, vérifiez que le client a droit à ce fichier précis, puis créez une URL présignée de courte durée.

Une URL présignée est une adresse HTTPS qui contient une signature et une date d'expiration dans ses paramètres. Spaces accepte cette signature comme autorisation pour une opération donnée. Ce mécanisme convient aux factures, aux exports de comptes et aux téléchargements réservés aux membres quand une brève possibilité de partage reste acceptable.

Le piège consiste à cacher une URL publique derrière un bouton réservé aux comptes connectés. Le bouton disparaît après déconnexion, mais le fichier reste public. Toute personne qui copie son adresse peut encore le récupérer. Il faut protéger le stockage aussi bien que la page.

Le projet compagnon contient deux comptes de démonstration et deux fichiers. Vous pouvez ainsi observer les contrôles d'accès sans installer une base de données. Il sert à répéter le parcours en local. Son authentification de démonstration ne remplace pas un système de comptes destiné à la production.

Choisir le comportement attendu pour vos fichiers

L'authentification répond à une question simple. Qui fait cette demande ? L'autorisation détermine ensuite si cette personne peut recevoir ce fichier. La connexion répond à la première question. Votre application doit encore répondre à la seconde avant de signer une URL.

Choisissez une URL publique pour les fichiers destinés à tout le monde. Une URL présignée convient si une personne autorisée peut recevoir un lien temporaire et partageable. Un relais applicatif authentifié convient si votre serveur doit vérifier l'accès à chaque nouvelle demande de téléchargement.

Ce relais utilise davantage de bande passante applicative et demande plus de travail d'exploitation. Il ne peut pas non plus reprendre un fichier déjà enregistré. Choisissez-le pour une exigence d'accès précise. Le simple fait d'appeler un document privé ne suffit pas à déterminer la bonne méthode.

Faites défiler horizontalement pour voir toutes les colonnes.

Trois méthodes de téléchargement
MéthodeUsage adaptéLimite
URL publiqueImages publiques, manuels ouverts, fichiers accessibles à tousToute personne qui connaît l'adresse peut télécharger.
Objet privé et URL présignéeExports de comptes avec une courte possibilité de partageLe lien reste réutilisable et partageable jusqu'à expiration.
Relais applicatif authentifiéContrôle obligatoire avant chaque demandeLe trafic traverse votre application. Les copies enregistrées échappent toujours à son contrôle.

Vérifier le prix de DigitalOcean Spaces

Tarifs vérifiés le 8 septembre 2026. Spaces Standard commence à 5 $ US par mois, avec 250 GiB de stockage et 1 024 GiB de transfert sortant inclus. Le stockage Standard supplémentaire coûte 0,02 $ US par GiB et par mois. Le transfert sortant supplémentaire coûte 0,01 $ US par GiB. Consultez les règles de facturation avant de créer le bucket. Ces volumes inclus sont partagés entre les buckets du compte. Chaque bucket ne reçoit pas un nouveau quota.

L'hébergement Next.js se paie séparément. Exécuter le projet sur votre ordinateur évite un nouvel hébergement applicatif pour cette répétition. La création des ressources Spaces peut cependant entraîner une facture. Estimez votre budget selon les fichiers conservés et les téléchargements attendus, pas seulement selon le nombre de comptes.

Pour estimer le transfert, multipliez la taille des fichiers par le nombre de téléchargements complets. Les nouvelles tentatives et les téléchargements répétés ajoutent du trafic. Une expiration courte ne transforme pas un lien en téléchargement unique et ne limite pas son nombre d'utilisations pendant sa validité.

Spaces convient si vous cherchez du stockage compatible S3 et utilisez déjà DigitalOcean. Ici, son avantage est la livraison directe avec peu de code applicatif. Ses limites sont le prix mensuel de base pour un très petit projet et le travail qui vous reste. Votre application doit encore gérer les autorisations, les abus et les comptes.

Créer un bucket Spaces privé et une clé limitée

Un objet correspond à un fichier stocké. Sa clé est son nom complet dans le bucket, avec son éventuel préfixe qui ressemble à un dossier. Une clé comme reports/iris.txt identifie un fichier. Elle ne prouve pas qu'Iris en est propriétaire. Votre application décide de ce droit séparément.

Utilisez un bucket distinct et des fichiers texte sans données sensibles pour cet exercice. Désactivez la liste publique des fichiers, mais ne considérez pas ce réglage comme une preuve de confidentialité. La liste concerne la découverte des objets. Leurs permissions contrôlent le téléchargement. Vérifiez donc aussi chaque fichier.

La permission Read permet la lecture et la liste des objets dans tout le bucket sélectionné. Elle ne limite pas la clé au fichier d'Iris. Votre contrôle de propriétaire impose cette limite plus précise. Les clés limitées ne se combinent pas avec une politique de bucket dans cette configuration. Utilisez le bucket dédié et examinez toute politique existante avant de reprendre ce montage.

  1. Créez un bucket Spaces avec un nom unique sans point dans la région choisie. Laissez le CDN désactivé pour cet exercice et notez le nom du bucket ainsi que sa région, par exemple nyc3.
  2. Envoyez deux fichiers texte inoffensifs avec les clés private/iris/report.txt et private/milo/report.txt. Rendez chaque objet privé et réglez ses métadonnées Cache-Control sur private, no-store. N'utilisez pas encore de données client.
  3. Créez une clé d'accès Spaces dédiée avec la permission Read limitée à ce bucket. L'application doit seulement lire les fichiers. Utilisez votre compte administrateur séparément pour les envois.
  4. Enregistrez l'identifiant et le secret de la clé dans le fichier local décrit par le projet. N'utilisez jamais de variable NEXT_PUBLIC_ pour ces secrets et ne les ajoutez pas à Git.
  5. Ouvrez l'URL d'origine sans signature d'un fichier dans une nouvelle session de navigateur. Vous devez obtenir un refus. Si le fichier se télécharge, corrigez ses permissions avant de continuer.

Lancer le projet avant de modifier votre application

Commencez par le projet complet ci-dessous. Il rassemble les variables de configuration, les commandes et les tests exécutables. Vous évitez ainsi de reconstruire une application à partir de fragments dispersés. Suivez son README dans l'ordre et utilisez la version de Node.js indiquée.

Le projet utilise l'authentification HTTP Basic avec deux comptes, iris et milo. Vous définissez leurs mots de passe dans des variables réservées au serveur. La fenêtre de connexion du navigateur suffit pour montrer l'identité en local. Elle ne fournit ni inscription, ni récupération de mot de passe, ni gestion complète des sessions.

Gardez cette démonstration sur localhost. Pour une application hébergée, remplacez-la par votre session vérifiée côté serveur et utilisez HTTPS. HTTP Basic encode les identifiants, mais ne les chiffre pas. Ce détail devient essentiel dès que la connexion quitte votre ordinateur.

  1. Clonez le dépôt compagnon et installez les dépendances verrouillées avec les instructions du README.
  2. Copiez .env.example vers .env.local. Renseignez SPACES_REGION, SPACES_BUCKET, SPACES_KEY, SPACES_SECRET, DEMO_IRIS_PASSWORD et DEMO_MILO_PASSWORD selon le README. Chaque mot de passe doit contenir au moins 24 caractères. Comparez les clés des fichiers aux objets envoyés.
  3. Lancez les tests locaux. Ils vérifient les décisions de l'application sans prouver que les permissions de votre bucket réel sont correctes.
  4. Démarrez le serveur et ouvrez http://127.0.0.1:3011. Cliquez sur Sign in to the demo, saisissez iris et son mot de passe, puis suivez Return to downloads. Demandez iris-report et vérifiez le contenu de votre fichier de test.
  5. Pour changer de compte, utilisez des profils de navigateur séparés ou les commandes de test du projet. Le navigateur peut mémoriser les identifiants Basic et fausser une vérification avec un autre compte.
Interface locale du projet avec les boutons de téléchargement Iris et Milo
Interface de démonstration locale. Cette capture ne vérifie pas un téléchargement réel depuis Spaces.

Comment Next.js signe une URL présignée Spaces

Le navigateur demande un identifiant de fichier propre à l'application. Le serveur authentifie le compte, retrouve cet identifiant dans son catalogue privé et compare ce compte au propriétaire. La signature arrive seulement après ces contrôles. Un fichier appartenant à un autre compte renvoie le même résultat introuvable qu'un identifiant inconnu.

Le serveur choisit le bucket, la clé de l'objet, le nom de téléchargement et l'expiration. Ne remplacez pas cette recherche par une route qui signe n'importe quelle clé fournie par le navigateur. Un simple compte valide pourrait alors demander les fichiers des autres clients.

Le projet utilise le SDK AWS pour JavaScript afin de signer une requête GetObject valable 60 secondes. GetObject signifie télécharger cet objet. Créer l'URL ne télécharge pas le fichier et ne prouve pas son existence. La vérification réelle reste donc nécessaire.

La signature utilise l'origine régionale Spaces et la configuration SDK du dépôt. Ne remplacez pas ensuite le nom de domaine par celui de votre CDN public. Le nom d'hôte participe à la signature. DigitalOcean précise aussi que les requêtes présignées ne profitent pas du cache de son CDN.

La réponse de l'API qui contient le lien utilise no-store. La requête de téléchargement demande également un cache privé sans stockage et une disposition en pièce jointe. Ces en-têtes réduisent le stockage involontaire dans les caches et demandent un téléchargement au navigateur. Ils n'empêchent pas le destinataire de garder ou de partager le fichier.

Le bouton demande un nouveau lien au moment du clic, puis dirige le navigateur vers cette adresse. Cette navigation vers une pièce jointe ne demande pas de règle CORS sur Spaces. Si vous récupérez ensuite le contenu dans JavaScript avec une requête entre origines différentes, il faudra configurer CORS pour ce nouvel usage. CORS ne remplace jamais l'autorisation d'accès au fichier.

Tester les requêtes qui doivent échouer

Un téléchargement réussi dit peu de choses sur la confidentialité. Le test utile vérifie qu'une mauvaise requête échoue sans recevoir de lien signé ni de contenu. Lancez les tests locaux du projet, puis répétez les vérifications qui dépendent du stockage avec votre propre bucket de démonstration.

Ces vérifications sont les critères de réussite de votre installation. Cet article ne prétend pas avoir testé le service cloud avec vos identifiants. Ne partagez pas les mots de passe, les URL signées complètes ou le contenu des fichiers dans vos captures et comptes rendus.

  1. Appelez l'API de téléchargement sans identifiants. Attendez un statut HTTP 401 et aucune URL signée.
  2. Connectez-vous avec iris et demandez milo-report. Attendez HTTP 404 sans URL signée. Demandez aussi un identifiant inconnu et vérifiez le même statut.
  3. Avec iris, demandez iris-report. Attendez une réponse API réussie, puis un fichier téléchargé. Vérifiez son contenu et pas seulement le statut HTTP. Vérifiez aussi les en-têtes du fichier, Cache-Control: private, no-store et Content-Disposition avec attachment.
  4. Réutilisez cette même URL signée avant son expiration. Elle peut encore fonctionner, même dans un navigateur sans connexion au compte. C'est le comportement attendu d'un lien qui donne accès à son détenteur.
  5. Conservez exactement cette URL, attendez plus de 60 secondes avec une petite marge, puis lancez une nouvelle requête GET. Attendez un refus. Ne recliquez pas sur Télécharger, car cela créerait une nouvelle URL.
  6. Demandez directement l'URL d'origine sans signature. Attendez un refus. Si cet objet a déjà été public sur un CDN, vérifiez aussi cet ancien chemin et traitez les éventuelles copies publiques en cache.

Corriger les erreurs sans rendre le bucket public

Un statut 401 de l'API indique généralement des identifiants manquants ou incorrects. Un statut 404 peut désigner un identifiant inconnu ou un fichier affecté à un autre compte. Cette ambiguïté est volontaire. Vérifiez le compte authentifié et le catalogue du serveur avant de toucher aux permissions du stockage.

Si l'API fournit une URL mais que Spaces refuse le fichier, vérifiez le bucket, la clé exacte de l'objet, la région, les permissions de la clé et l'horloge de votre ordinateur. Une signature correcte peut viser un objet absent. Un code 403 ne prouve pas toujours l'existence du fichier et ne justifie pas à lui seul des permissions plus larges.

Une erreur de signature peut aussi venir d'une URL modifiée, d'un mauvais hôte ou d'une méthode différente. Testez une URL GetObject avec GET. Une commande qui envoie HEAD formule une autre requête et peut produire un échec trompeur.

Un lien expiré demande une nouvelle vérification d'autorisation et une nouvelle URL. Invitez la personne à revenir sur la page et à cliquer de nouveau sur Télécharger. Gardez les détails techniques dans des journaux protégés et affichez une instruction courte pour réessayer.

Remplacer les limites de démonstration avant la production

Reliez la route à votre véritable session de connexion vérifiée par le serveur. Consultez votre base de données à chaque demande de signature pour retrouver le propriétaire ou le droit d'achat. Si l'abonnement est terminé, refusez la prochaine demande. Cacher un identifiant dans une page ne constitue pas un contrôle.

Limitez le rythme de création des liens et surveillez les téléchargements inhabituels. Écartez les paramètres signés des statistiques, du suivi des erreurs et des journaux du serveur intermédiaire. Une URL signée complète est un secret temporaire. Sa possession suffit à l'utiliser.

Décidez si une possibilité de partage de 60 secondes convient à votre produit. Votre application vérifie les droits au moment de créer le lien. Elle ne les revérifie pas à chaque utilisation de celui-ci. Retirer un droit bloque les nouveaux liens quand votre contrôle le prend en compte, mais un lien existant peut rester utilisable jusqu'à expiration.

L'expiration n'efface pas une copie enregistrée. Elle ne doit pas non plus être présentée comme un arrêt garanti d'un transfert déjà commencé. Si vous exigez un contrôle plus strict des nouvelles requêtes, étudiez le relais authentifié décrit plus haut et définissez le traitement des téléchargements en cours.

Je choisirais cette méthode pour des exports ordinaires de comptes après réussite des tests de refus. Pour un document qui ne doit jamais être accessible par un lien transféré, même brièvement, je choisirais un contrôle de session à chaque demande. Mieux vaut trancher cette exigence avant de payer le stockage.

Le prochain résultat à obtenir

Terminez avec un fichier de démonstration privé, un téléchargement autorisé et des preuves que les requêtes interdites échouent. Ajoutez ensuite votre connexion réelle et votre recherche de propriétaire avant d'introduire des données client. Cette progression permet de découvrir les erreurs graves quand les fichiers sont encore sans importance.

Gardez le README compagnon ouvert pendant votre première réalisation pour retrouver les commandes et répéter les contrôles. Si cette application diffuse aussi des fichiers publics, le guide ci-dessous décrit cet autre parcours.

Les URL présignées Spaces sont-elles à usage unique ?

Non. Une URL présignée reste réutilisable et partageable pendant sa validité. Choisissez une expiration courte et contrôlez chaque demande de nouveau lien. Un jeton à usage unique dans votre application ne rend pas unique une URL Spaces déjà fournie.

La déconnexion annule-t-elle un téléchargement ?

La déconnexion n'invalide pas une URL présignée existante. Spaces vérifie la requête signée, pas votre session applicative. Refusez les nouveaux liens quand le droit prend fin et choisissez une expiration adaptée. Vous ne pouvez pas reprendre une copie déjà enregistrée.

Faut-il un CDN ou une règle CORS pour ces téléchargements ?

Ce guide utilise directement l'origine régionale. DigitalOcean précise que son CDN ne met pas les requêtes présignées en cache. Naviguer vers une pièce jointe ne demande pas de règle CORS. Lire son contenu depuis JavaScript entre origines différentes constitue un autre usage.

Une URL signée prouve-t-elle que le fichier existe ?

Non. Le SDK peut signer une requête sans vérifier ni télécharger l'objet. Testez le lien avec votre bucket et examinez le contenu reçu. Si la signature réussit mais le téléchargement échoue, vérifiez la clé du catalogue et les permissions du fichier.

Vérifier le résultat

Résultat attendu
Le propriétaire reçoit le bon fichier. Sans identifiants, avec un autre utilisateur, un lien expiré ou une URL non signée, la lecture échoue.
Arrêter si
Arrêtez si un fichier est public, si un autre utilisateur obtient son lien, si une nouvelle requête GET accepte le lien expiré ou si un secret atteint le navigateur ou les journaux.
Étape suivante
Remplacez les comptes de démonstration par la session et les droits de votre application avant le déploiement. Répétez les tests sous HTTPS.