2015-01-27 10 views
9

Ich habe mehrere FileFields in meiner Django-App, die verschiedenen Benutzern gehören können. Ich bin auf der Suche nach einer guten Möglichkeit, den Zugriff auf Dateien für Benutzer, die nicht der Besitzer der Datei sind, zu beschränken.Beschränken des Zugriffs auf private Dateidownloads in Django

Was ist der beste Weg, dies zu erreichen? Irgendwelche Ideen?

+0

ich Ihnen vorschlagen zu folgen [Wie eine Datei privat zu machen, indem Sie die URL zu sichern, dass nur authentifizierte Benutzer sehen können] (http: //stackoverflow.com/questions/28007770/), aber Sie müssen Ihre eigene Methode implementieren, um anderen Benutzern den Zugriff zu verwehren ...! –

Antwort

7

Leider @ Mikko Lösung kann nicht tatsächlich in einer Produktionsumgebung arbeiten, da django nicht für die Dateien dient. In einer Produktionsumgebung müssen Dateien von Ihrem HTTP-Server (z. B. apache, nginx usw.) und nicht von Ihrer Anwendung/django Server (z. B. uwsgi, gunicorn, mod_wsgi usw.) bedient werden.

nicht sehr einfach: Sie benötigen eine Möglichkeit für Ihren HTTP-Server, den Anwendungsserver zu fragen, ob es in Ordnung ist, eine Datei an einen bestimmten Benutzer zu liefern. Wie Sie verstehen, erfordert dies Änderungen an Ihrer Anwendung und Ihrem http-Server.

Die beste Lösung für das obige Problem ist django-sendfile (https://github.com/johnsensible/django-sendfile), die den X-SendFile-Mechanismus verwendet, um das Obige zu implementieren. Ich kopiere aus der Projektbeschreibung:

Dies ist ein Wrapper um Web-Server-spezifische Methoden zum Senden von Dateien an Web-Clients. Dies ist nützlich, wenn Django die mit Berechtigungen verknüpften Dateien prüfen muss, aber nicht die tatsächlichen Bytes der Datei selbst bereitstellen möchte. Das heißt, dass Django nicht dafür gedacht ist, große Dateien zu liefern.

Um mehr über die senfile Mechanismus zu verstehen, lesen Sie bitte diese Antwort: Django - Understanding X-Sendfile

1

Im Allgemeinen routen Sie keine privaten Dateien durch normale statische Dateien, die direkt über Apache, Nginx oder den von Ihnen verwendeten Webserver geliefert werden. Schreiben Sie stattdessen eine benutzerdefinierte Django-Ansicht, die die Berechtigungsprüfung behandelt und die Datei dann als Streaming-Download zurückgibt.

  • Stellen Sie sicher, dass Dateien in einem speziellen Ordner privaten Ordner und nicht MEDIA_URL oder STATIC_URL

  • einen Blick Schreiben durch Djangos ausgesetzt, die

    • prüfen wird, dass der Benutzer Zugriff auf die hat Datei in Ihrer Sicht Logik

    • Öffnen Sie die Datei mit Pythons open()

    • Return HTTP-Antwort, die das Handle als Parameter der Datei bekommt http.HttpResponse(_file, content_type="text/plain")

Zum Beispiel sehen download()here.

2

Wenn Sie nur moderate Sicherheit benötigen, wäre mein Ansatz die folgende sein:

1) Wenn der Benutzer die Datei-Uploads , erzeugen Sie einen schwer zu erratenden Pfad dafür. Zum Beispiel können Sie einen Ordner mit einem zufällig generierten Namen für jede hochgeladene Datei in Ihrem/statischen Ordner erstellen. Sie können dies tun, ziemlich einfach diesen Beispielcode verwenden:

file_path = "/static/" + os.urandom(32).encode('hex') + "/" + file_name 

Auf diese Weise wird es sehr schwer sein, zu erraten, wo die Dateien anderer Benutzer gespeichert sind.

2) Verknüpfen Sie in der Datenbank den Besitzer mit der Datei. Ein Beispiel Schema kann sein:

uploads(id, user_id, file_path)

3) eine Eigenschaft für Ihre FileFields im Modell, um den Zugriff auf die Datei auf diese Weise zu beschränken:

class YourModel(models.Model) 
    _secret_file = models.FileField() 

    def get_secret_file(self): 
     # check in db if the user owns the file 
     if True: 
      return self._secret_file 
     elif: 
      return None # or something meaningful depanding on your app 

    secret_file = property(get_secret_file) 
+0

danke sehr sehr hilfreich – soField

0

dies am besten durch die behandelt wird Server, z nginx secure link module (nginx muss mit --with-http_secure_link_module kompiliert werden)

Beispiel aus der Dokumentation:

location /some-url/ { 
    secure_link $arg_md5,$arg_expires; 
    secure_link_md5 "$secure_link_expires$uri$remote_addr some-secret"; 

    if ($secure_link = "") { 
     return 403; 
    } 

    if ($secure_link = "0") { 
     return 410; 
    } 

    if ($secure_link = "1") { 
     // authorised... 
    } 
} 

Die Datei wie zugegriffen werden würde:

/some-url/some-file?md5=_e4Nc3iduzkWRm01TBBNYw&expires=2147483647 

(Diese beiden zeitlich befristet sein würde und gebunden an den Benutzer an dieser IP-Adresse).

das Token für den Benutzer wie etwas passieren generieren verwenden würde:

echo -n 'timestamp/some-url/some-file127.0.0.1 some-secret' | \ 
openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d = 
Verwandte Themen