Servir un fichier protégé avec Django et Nginx


Certains fichiers sont réservés à des personnes ayant payé, avec un compte, ou encore protégés par un mot de passe. Problème: django gère l’authentification mais ne doit pas gérer l’upload car c’est le taff du serveur en front end.

Etape 1: configurer Nginx

Je suppose ici que vous avez une config Django classique avec Nginx qui fait un proxy passe vers un serveur WSGI type cherrypy, gunircorn, uwsgi, etc.

Dans votre fichier de config Nginx, rajoutez ceci:

server {
   ...
   location /secure_upload/{
       internal;
       alias /chemin/absolu/vers/dossier/du/projet/media;
   }
}

La directive internal s’assure qu’une requête extérieur ne peut pas demander d’accéder à cette adresse.

Etape 2: authentifier et rediriger avec une vue Django

Dans cet exemple, on sert uniquement le fichier aux utilisateurs authentifiés. Mais on pourrait très bien le faire sur la saisie d’un code unique, vérifier les droits d’accès, etc. J’ai juste choisi le cas le plus simple.

from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
from django.views import static
from django.conf import settings
 
@login_required() # on accepte uniquement les requête authentifiées
def serve_secure_static(request, path):
 
    # en mode debug, on demande à Django de servir le fichier histoire de pas
    # être forcé de setuper nginx sur sa machine de dev
    if settings.DEBUG:
        return static.serve(request, path, settings.SECURE_MEDIA_ROOT)
 
    # Sinon on retourne une réponse VIDE avec en header le chemin de l'url
    # de l'upload interne
    # Nginx va l'intercepter, réaliser qu'il faut qu'il upload ce qu'il y
    # a à cette URL et faire le reste du boulot
    response = HttpResponse()
    response['X-Accel-Redirect'] = '/secure_upload/%s' % path
    return response

Etape 3 : configurer Django

Evidément il vous faut dans le settings.py:

MEDIA_ROOT = "/chemin/absolu/vers/dossier/du/projet/media"
SECURE_MEDIA_ROOT = os.path.join(MEDIA_ROOT, 'secure')

Les dossiers doivent être créés à la mano.

Et dans urls.py:

url(r'^download/(?P
.*)$', server_secure_static)

2 thoughts on “Servir un fichier protégé avec Django et Nginx

  • Gkar

    J’allais vous demander pourquoi ne pas utiliser X-SendFile quand j’ai vu que c’était l’équivalent sous Nginx (ie http://wiki.nginx.org/XSendfile)

    Donc pour les gens sous apache/lighttpd/cherokee il faut écrire:

    response[‘X-Accel-Redirect’] = ‘full/path/vers/le/fichier/secure’

    et le chemin en question n’a pas besoin d’être dans la configuration du serveur (à vérifier).

    En tout cas je prends note pour quand j’aurais enfin le temps de passer à Nginx.

  • Guillaume Duval

    Une petite erreur s’est glissée dans le morceau de config du serveur Nginx:

    server {
       ...
       location /chemin/absolu/vers/dossier/du/projet/media {
           internal;
           alias /secure_upload/;
       }
    }

    Il faut inverser /chemin/absolu/vers/dossier/du/projet/media et /secure_upload/

Comments are closed.

Des questions Python sans rapport avec l'article ? Posez-les sur IndexError.