简体   繁体   English

Django + NGINX 使用 X-Accel-redirect 保护媒体链接不起作用

[英]Django + NGINX Protecting Media Links using X-Accel-redirect not working

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.我正在尝试通过 Django 视图获取图像链接以进行额外的安全检查,以便只有具有正确权限的人才能访问该链接。

Currently, this is the setup: an User X uploads a photo from his account.目前,这是这样的设置:用户 X 从他的帐户上传一张照片。 The files get saved in media/images/ folder.文件保存在 media/images/ 文件夹中。 And the django CreateView redirects to 'view/<id_of_image_in_db>' --> Which triggers Django Detailview function.并且 django CreateView重定向到 'view/<id_of_image_in_db>' --> 触发 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. detail.html 获取照片object 并在卡片中渲染。

    {% 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>当页面被渲染时,“{{photos.image.url}}”将是 /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.这一切都可以在 NGINX 的生产中正常工作,默认方法是由 NGINX 提供图像,而无需与 Django 服务器通信。

Working NGINX Config:工作 NGINX 配置:

    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.现在,如果您右键单击图像并获取在详细视图中渲染的图像 URL 和 go 到一个 incog window 并粘贴链接,该图像将显示访问者。 Because there is no communication from NGINX with django whether proper permission exists.因为没有来自 NGINX 与 django 的通信是否存在适当的权限。

Tried Solutions:尝试过的解决方案:

Based on many answers, I tried using X-Accel-redirect and been failing miserably to get it to work.基于许多答案,我尝试使用 X-Accel-redirect 并且惨遭失败以使其正常工作。

**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示例 GitHub 项目在这里: 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 1 - 使渲染图像的所有视图都包含 ID 标签,以便更容易查找访问权限

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)
        x = context[self.context_object_name]
        context['safeURLs'] = x.image.url.replace('/images','/images/'+str(x.id))
        context['userName'] = self.request.user
        return context

2 - Urls.py Modification - So that all /media/* urls go through django and not nginx 2 - Urls.py 修改 - 使所有 /media/* url go 到 django 而不是 nginx

url(r'^media/(?P<path>.*)', login_required(views.media_access), name='media'),

3 - In views.media_access check for proper access 3 - 在 views.media_access 检查正确的访问

def media_access(request, path):
    #--> Check For Access Code
    if access_granted:
        response = HttpResponse()
        del response['Content-Type']
        response['X-Accel-Redirect'] = '/protected/' + path.replace(str(id)+'/','')
                #/protected/ will go through Nginx
                # Remove the ID that we tagged while rendering the object
        print('Final Response', response['X-Accel-Redirect'])
        return response
    else:
        return HttpResponseForbidden('Not authorized to access this media.')

4 - Final nail in the coffin - NGINX Update 4 - 棺材里的最后一颗钉子 - NGINX 更新

    location ^~ /protected/ {
        internal;
        alias /home/ubuntu/photoApp/media/;
    }

        location / {
        # Other Proxy Stuff
        proxy_buffering off;
        }


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. 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.唯一的缺点是所有 ListView 和 DetailView 都必须用 object ID 标记,然后再剥离。

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我已经用工作代码更新了 github 中的项目: https://github.com/IamVNIE/django-photoapp-project

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM