I am trying to get the image links delivered via Django Views to undergo additional security checks so that only the person with the correct permission can access the link.
Currently, this is the setup: an User X uploads a photo from his account. The files get saved in media/images/ folder. And the django CreateView redirects to 'view/<id_of_image_in_db>' --> Which triggers Django Detailview function .
class PhotosHDView(DetailView):
model = MYPhotos
template_name = 'detail.html'
context_object_name = 'photos'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['userName'] = self.request.user
return context
The detail.html gets the photos object and renders in card.
{% block content %}
<div class="container mx-auto">
<div class="card ">
<img src="{{photos.image.url}}" class="card-img-top" alt="...">
</div>
</div>
{% endblock %}
When the page is rendered "{{photos.image.url}}" will be /media/images/<image_name>
This all works fine in production with NGINX with the default method where the images are served by NGINX without communicating with Django server.
Working NGINX Config:
location /media/ {
autoindex off;
alias /home/ubuntu/photoApp/media/;
}
Now if you right-click the image and get the image URL rendered in detail view and go to an incog window and paste the link, the image will be displayed irrespective of who is accessing it. Because there is no communication from NGINX with django whether proper permission exists.
Tried Solutions:
Based on many answers, I tried using X-Accel-redirect and been failing miserably to get it to work.
**Added in urls.py**
re_path(r'^media/$',login_required(views.sid), name='SecureImages' ),
** sid to function when the path is true **
def sid(request):
print(' Triggered SID FUNCTION', request)
response = HttpResponse()
# Showing cat image irrespective of image requested--> Simple Test
# Once it works, get the image requested from request and send the redirect
response['X-Accel-Redirect'] ='media/images/cat.jpeg'
return request
** NGINX Config Changes **
location /media/ {
autoindex off;
internal; #<-- Added this
alias /home/ubuntu/photoApp/media/;
}
After these changes, none of the images are shown even when accessed by the proper User.
What am I doing wrong ?? Please suggest a solution for this.
Sample GitHub project is here: https://github.com/IamVNIE/django-photoapp-project
Finally Got it to Work..
1 - Make All the views that render images to include ID tag so that it becomes easier to lookup for access
2 - Urls.py Modification - So that all /media/* urls go through django and not nginx
3 - In views.media_access check for proper access
4 - Final nail in the coffin - NGINX Update
Basically made all /media/ requests to go django --> Checks Access --> django tags /media/ as /protected/ --> NGINX picks up /protected/ and serves the file from media folder.
The only drawback is all the ListView and DetailView have to be tagged with object ID and later on stripped away.
I felt without this tag, we would have to make query to search the DB for the file name to lookup proper owner, which would make the system inefficient.
Let me know if this is the correct way.
I have updated the project in github with working code: https://github.com/IamVNIE/django-photoapp-project