skip to Main Content

I am trying to make a project and have some media files which should only be accessed by their owner.
In production, media and static files are served by apache (or nginx but I am using apache).

I was looking for some solutions and I am not able to apply.

On djangosnippets website, I found this code,

from mod_python import apache
from django.core.handlers.base import BaseHandler
from django.core.handlers.modpython import ModPythonRequest


class AccessHandler(BaseHandler):
    def __call__(self, req):
        from django.conf import settings

        # set up middleware
        if self._request_middleware is None:
            self.load_middleware()
        # populate the request object
        request = ModPythonRequest(req)
        # and apply the middleware to it
        # actually only session and auth middleware would be needed here
        for middleware_method in self._request_middleware:
            middleware_method(request)
        return request


def accesshandler(req):
    os.environ.update(req.subprocess_env)

    # check for PythonOptions
    _str_to_bool = lambda s: s.lower() in ("1", "true", "on", "yes")

    options = req.get_options()
    permission_name = options.get("DjangoPermissionName", None)
    staff_only = _str_to_bool(
        options.get("DjangoRequireStaffStatus", "on")
    )
    superuser_only = _str_to_bool(
        options.get("DjangoRequireSuperuserStatus", "off")
    )
    settings_module = options.get("DJANGO_SETTINGS_MODULE", None)

    if settings_module:
        os.environ["DJANGO_SETTINGS_MODULE"] = settings_module

    request = AccessHandler()(req)
    if request.user.is_authenticated():
        if superuser_only and request.user.is_superuser:
            return apache.OK
        elif staff_only and request.user.is_staff:
            return apache.OK
        elif permission_name and request.user.has_perm(
            permission_name
        ):
            return apache.OK
    return apache.HTTP_UNAUTHORIZED

But I am not able to install mod_python. Please tell me how to do that first

And I changed my .conf file for apache which is as below.

<VirtualHost *:80>



    ServerName podcast.com
    ServerAdmin [email protected]
    DocumentRoot /home/username/Documents/secret_media

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    Alias /static /home/username/Documents/secret_media/static
    <Directory /home/username/Documents/secret_media/static>
        Require all granted
    </Directory>

    Alias /media /home/username/Documents/secret_media/media
    <Directory /home/username/Documents/secret_media/media>
        Require all granted
    </Directory>

    <Directory /home/username/Documents/secret_media/secret_media>
        <Files wsgi.py>
            Require all granted
        </Files>
    </Directory>






    WSGIScriptAlias / /home/username/Documents/secret_media/secret_media/wsgi.py
    WSGIDaemonProcess secret_media python-path=/home/username/Documents/secret_media python-home=/home/username/Documents/secret_media/venv
    WSGIProcessGroup secret_media

    LoadModule auth_basic_module modules/mod_auth_basic.so
    LoadModule authz_user_module modules/mod_authz_user.so



    <Location "/media/images">
        PythonPath /home/username/Documents/secret_media
        PythonOption DJANGO_SETTINGS_MODULE secret_media.settings
        PythonAccessHandler secret_media.wsgi.py #this should point to accesshandler
        SetHandler None
    </Location>



</VirtualHost>

There are some settings which are repeated, don’t know why, please explain

2

Answers


  1. One way to do it is using a so-called X-Sendfile.
    In simple words:

    1. User requests URL to get a protected file (so you need to keep your public and protected files separately, and then either proxy a request to Django for protected files, or serve files directly from the apache/nginx if they are public)
    2. Django view decides which file to return based on URL, and checks user permission, etc.
    3. Django returns an HTTP Response with the ‘X-Sendfile’ header set to the server’s file path
    4. The web server finds the file and returns it to the requester

    The setup will be different for nginx and apache, according to my findings you need to install mod_xsendfile for apache, nginx supports it out of the box. Hopefully, that helps, ask any additional questions if needed.

    Login or Signup to reply.
  2. X-Sendfile

    I do not know about the method you use above, but I have been using mod_xsendfile to do the same. Whats the principle: request to a url is handeled by a view that checks access rights … the view returns a response with a key "X-Sendfile" & file … this triggers Apache on the way back to serve the media file.

    I just show you the code without testing syntax …. please ask if something is not clear

    Apache httpd.conf

    LoadModule xsendfile_module modules/mod_xsendfile.so
    

    in Apache remove the usual "alias media …"

    Apache httpd-vhosts.conf

    <VirtualHost *:80>
        
        # ... all your usual Django Config staff
    
    
        # remove the usual alias /media/  
        # Alias /media/ d:/WEBSPACES/dieweltdahinter_project/media/
    
        XSendFile on
        XSendFilePath D:/your_path/media/
        <Directory "D:/your_path/media">
               Order Deny,Allow
               Allow from all
        </Directory>
    </VirtualHost>
    

    urls.py

    urlpatterns = [
         .....,
    
       re_path(r'^media/(?P<folder>[A-Za-z0-9-_]+)/(?P<filename>[A-Za-z0-9-_]+).(?P<extension>[A-Za-z0-9]+)/?$', app_views.media_xsendfile, name='media-xsendfile'),
      
         .....
    ]
    

    views.py

    
    # add decorators to manage access 
    #
    def media_xsendfile(request, folder='', filename=None, extension=None): 
     
        # add an kind of user check ....
       
        # only server certain type of files
        if extension in ('jpg', 'png', 'gif'):
            response['Content-Type'] = 'image/'+extension
        elif extension == 'mp3':
            response['Content-Type'] = 'audio/mpeg'
        else:
            return
    
        if not folder == '':
            folder = '/'+folder+'/'
    
       response = HttpResponse()
       # this is the part of the response that Apache reacts upon:
       response['X-Sendfile'] = smart_str(settings.MEDIA_ROOT + folder + filename + "." + extension)
       # need to handover an absolute path to your file to Apache!!
    
       return response
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search