Home:ALL Converter>Serve protected media files with django

Serve protected media files with django

Ask Time:2016-09-28T18:16:03         Author:user2496550

Json Formatter

I'd like Django to serve some media files (e.g. user-uploaded files) only for logged-in users. Since my site is quite low-traffic, I think I will keep things simple and do not use django-sendfile to tell Nginx when to serve a file. Instead I'll let Django/Gunicorn do the job. To me this seems a lot simpler and for a low traffic site this maybe more secure.

But what is the best way to organize the file storage location? Media files are all stored below MEDIA_ROOT and this directory is served by Nginx in production. If I upload my files to MEDIA_ROOT/protected/ I have to tell Nginx not to serve the files in the subdirectory protected.

But is this a good idea? It seems a litte risky to me to allow Nginx access /media/ in the first place and then protect the subdirectory /media/protected/. Wouldn't it be better not to use a subdirectory of MEDIA_ROOT to store protected files?

But if I try something like this quick-and-dirty in my model:

upload_to='../protected/documents/%Y/%m/'

Django complains:

SuspiciousFileOperation at /admin/core/document/add/
The joined path (/home/me/projects/project/protected/documents/2016/09/test.file) is located outside of the base path component (/home/me/projects/project/media)

So I thing it is not good practice to "leave" the MEDIA_ROOT.

What is the best solution to store and serve protected media files?

Author:user2496550,eproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/39744587/serve-protected-media-files-with-django
Renjith Thankachan :

Serving media files ( that may be large files) from view directly is not good. You can use sendfile extension available in nginx server; a sample nginx configuration is like below.\n\n location /projects/project/media/{\n # this path is not public\n internal;\n # absolute path\n alias /projects/project/media/;\n }\n\n\nchange your view to\n\n@login_required\ndef serve_protected_document(request, file):\n document = get_object_or_404(ProtectedDocument, file=\"protected/documents/\" + file)\n\n # Split the elements of the path\n path, file_name = os.path.split(file)\n\n response = HttpResponse()\n response[\"Content-Disposition\"] = \"attachment; filename=\" + file_name\n # nginx uses this path to serve the file\n response[\"X-Accel-Redirect\"] = document.name # path to file\n return response\n\n\nLink: More details on configuring sendfile extension on nginx is here ",
2017-04-05T06:31:24
user2496550 :

I now came up with the following solution:\n\nI have this in my Django settings:\n\nMEDIA_ROOT = \"/projects/project/media/\"\nMEDIA_URL = \"/media/\n\n\nIn my models I do either:\n\ndocument = models.FileField(upload_to=\"public/documents\")\n\n\nor\n\ndocument = models.FileField(upload_to=\"protected/documents\")\n\n\nThis way, I now have the two subdirectories 'public' and 'protected' in my media files directory.\n\nNginx or Djangos development server only serves the files in the 'public' subdirectory.\n\nFor Djangos development server:\n\nif os.environ[\"ENVIRONMENT_TYPE\"] == 'development':\n urlpatterns += static(settings.MEDIA_URL + \"public/\", document_root=settings.MEDIA_ROOT + \"public/\")\n\n\nAnd for Nginx (used in production):\n\nlocation /media/public/ {\n alias /projects/project/media/public/;\n}\n\n\nWhen I want to serve a protected document, I do the following:\n\nIn urls.py:\n\nurl(r'^media/protected/documents/(?P<file>.*)$', core.views.serve_protected_document, name='serve_protected_document'),\n\n\nAnd in views.py:\n\n@login_required()\ndef serve_protected_document(request, file):\n document = get_object_or_404(ProtectedDocument, file=\"protected/documents/\" + file)\n\n # Split the elements of the path\n path, file_name = os.path.split(file)\n\n response = FileResponse(document.file,)\n response[\"Content-Disposition\"] = \"attachment; filename=\" + file_name\n\n return response\n\n\nI would appreciate any comments! Are there better ways to implement this?",
2016-09-28T13:38:30
yy