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

前端 未结 3 1784
花落未央
花落未央 2020-12-08 16:43

I was wondering if there is a way to secure an image or a file to be hidden when it is not authenticated.

Suppose there is an image in my website which can only be s

相关标签:
3条回答
  • 2020-12-08 17:25

    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.

    0 讨论(0)
  • 2020-12-08 17:31

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

    0 讨论(0)
  • 2020-12-08 17:44

    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
    
    0 讨论(0)
提交回复
热议问题