How do you Require Login for Media Files in Django

TomFuertes picture TomFuertes · Jul 11, 2009 · Viewed 13.2k times · Source

I'm serving "sensitive" information in downloadable PDF's and Spreadsheets within a user registration section of a site.

Is there a way to allow the django authentication to secure this media without serving it (and not have to manually login using basic auth)?

I'm guessing theres (fingers crossed) not a way to do it with the psuedo code below, but it helps better illustrate the end goal.

#urls.py
(r'^protected_media/(?P<filename>.*)$', 'protected_media')

#views.py
from django.contrib.auth.decorators import login_required

@login_required
def protected_media(request, filename):
    # @login_required bounces you out to the login url
    # if logged in, serve "filename" from Apache

Answer

ars picture ars · Jul 11, 2009

It seems to me that the method you outlined in your code should work. It's really no different than any other protected resource: your views can serve files from disks, records from databases, rendered templates or anything. Just as the login_required decorator prevents unauthorized access to other views, it will prevent such access to your view serving protected media.

Am I missing something from your question here? Please clarify if that's the case.

EDIT: With regard to the django doc link in your comment: that's the method for simply serving any request file from a particular directory. So, in that example URLS like /site_media/foo.jpg, /site_media/somefolder/bar.jpg will automatically look for files foo.jpg and somefolder/bar.jpg under document_root. Basically, every thing under document_root will be publicly available. That's obviously insecure. So you avoid that with your method.

It's also considered inefficient because django is just adding a lot of unnecessary overhead when all you need is something like Apache to take a URL request and map it to a file on the hard drive. (You don't need django sessions, request processing, etc.)

In your case, this may not be such a big concern. First, you've secured the view. Second, it depends on your usage patterns. How many requests do you anticipate for these files? You're only using django for authentication -- does that justify other overhead? If not, you can look into serving those files with Apache and using an authentication provider. For more on this, see the mod_wsgi documentation:

There are similar mechanisms available under mod_python I believe. (Update: just noticed the other answer. Please see Andre's answer for the mod_python method.)

EDIT 2: With regard to the code for serving a file, please see this snippet:

The send_file method uses a FileWrapper which is good for sending large static files back (it doesn't read the entire file into memory). You would need to change the content_type depending on the type of file you're sending (pdf, jpg, etc).