[Fixed]-How to to make a file private by securing the url that only authenticated users can see


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

def protected_serve(request, path, document_root=None):
        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…


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

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
        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
        # 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.



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

def sekret_view(request, path=None):
   filename = os.path.basename(path)
   response = HttpResponse(FileWrapper(open(path)),
   response['Content-Length'] = os.path.getsize(path)
   return response

Leave a comment