PROJET AUTOBLOG


Sam et Max

source: Sam et Max

⇐ retour index

Servir un fichier protégé avec Django et Nginx

vendredi 21 septembre 2012 à 15:53

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 /chemin/absolu/vers/dossier/du/projet/media {
       internal;
       alias /secure_upload/;
   }
}

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<path>.*)$', server_secure_static)