11π
By securing any media file not to serve by anonymous user, better way url protection.
Code ( Updated ):
from django.conf.urls import patterns, include, url
from django.contrib.auth.decorators import login_required
from django.views.static import serve
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.shortcuts import HttpResponse
@login_required
def protected_serve(request, path, document_root=None):
try:
obj = Photobox.objects.get(user=request.user.id)
obj_image_url = obj.image.url
correct_image_url = obj_image_url.replace("/media/", "")
if correct_image_url == path:
return serve(request, path, document_root)
except ObjectDoesNotExist:
return HttpResponse("Sorry you don't have permission to access this file")
url(r'^{}(?P<path>.*)$'.format(settings.MEDIA_URL[1:]), protected_serve, {'file_root': settings.MEDIA_ROOT}),
Note: previously any logged in user can access any page, now this update restrict non user to view other filesβ¦
3π
It would be better to handle just the authentication, and let your webserver handle the serving of files. Itβs probably good to put them in a different directory than your settings.MEDIA_ROOT
, to prevent your webserver from serving the files before you handle the request, e.g. project_root/web-private/media/
.
import os
@login_required
def protected_file(request, path):
# set PRIVATE_MEDIA_ROOT to the root folder of your private media files
name = os.path.join(settings.PRIVATE_MEDIA_ROOT, path)
if not os.path.isfile(name):
raise Http404("File not found.")
# set PRIVATE_MEDIA_USE_XSENDFILE in your deployment-specific settings file
# should be false for development, true when your webserver supports xsendfile
if settings.PRIVATE_MEDIA_USE_XSENDFILE:
response = HttpResponse()
response['X-Accel-Redirect'] = filename # Nginx
response['X-Sendfile'] = filename # Apache 2 with mod-xsendfile
del response['Content-Type'] # let webserver regenerate this
return response
else:
# fallback method
from django.views.static import serve
return serve(request, path, settings.PRIVATE_MEDIA_ROOT)
As your webserver is way better at serving static files than Django, this will speed up your website. Check django.views.static.serve
for an idea how to sanitize file names etc.
- How to use Pagination in a Non-Generic View/Viewset?
- Django: model has two ManyToMany relations through intermediate model
- Django-paypal setup
- Deciding and implementing a trending algorithm in Django
1π
The easiest option is to serve the file from django, and then add the @login_required
decorator to the view, like this:
import os
import mimetypes
from django.core.servers.basehttp import FileWrapper
from django.contrib.auth.decorators import login_required
@login_required
def sekret_view(request, path=None):
filename = os.path.basename(path)
response = HttpResponse(FileWrapper(open(path)),
content_type=mimetypes.guess_type(path)[0])
response['Content-Length'] = os.path.getsize(path)
return response