【问题标题】:Django and Nginx X-accel-redirectDjango 和 Nginx X-accel-redirect
【发布时间】:2018-02-02 23:32:37
【问题描述】:

到目前为止,我一直在尝试保护 Django 的媒体文件,但没有成功!我只是想让它只有管理员用户可以访问媒体文件夹。这是我的 Nginx 文件。

server {
    listen 80;
    server_name xxxxxxxxxx;

    location = /favicon.ico {access_log off; log_not_found off;}
    location /static/ {
          alias /home/{site-name}/static_cdn/;
   }
   location /media/ {
          internal;
          root /home/{site-name}/;
   }

   location / {
this is setup and working. Didn't include Code though

}

我的网址文件

urlpatterns = [
    url(r'^media/', views.protectedMedia, name="protect_media"),
] 

我的看法

def protectedMedia(request):

    if request.user.is_staff:
        response = HttpResponse()
        response['Content-Type'] = ''
        response['X-Accel-Redirect'] = request.path
        return response

    else:
        return HttpResponse(status=400)

这会产生 404 Not Found Nginx 错误。这里有什么明显的错误吗?谢谢!

顺便说一句,我尝试在 Nginx 设置中将 /media/ 添加到根 URL 的末尾。

【问题讨论】:

  • 查看您的配置,问题似乎是此答案中确定的问题:stackoverflow.com/a/45774975/1081569。受保护视图的 URL 不能与 nginx 配置中的 URL 相同。
  • 谢谢,@PauloAlmeida。我对您发送给我的链接进行了一些更改,并设法使其正常工作!

标签: django ubuntu nginx sendfile django-media


【解决方案1】:

感谢@Paulo Almeida,这就是解决此问题的方法。

在 nginx 文件中,我也更改了之前的内容...

   location /protectedMedia/ {
          internal;
          root /home/{site-name}/;
   }

我的网址是...

url(r'^media/', views.protectedMedia, name="protect_media"),

视图是...

def protectedMedia(request):

    if request.user.is_staff:
        response = HttpResponse(status=200)
        response['Content-Type'] = ''
        response['X-Accel-Redirect'] = '/protectedMedia/' + request.path
        return response

    else:
        return HttpResponse(status=400)

这很完美!现在只有管理员用户可以访问存储在我的媒体文件夹中的媒体文件。

【讨论】:

  • 小心。对我来说,主要的陷阱是别名/根和斜杠的细微差别!看这里:nginx.com/resources/wiki/start/topics/examples/xsendfile - 必须真正集中精力才能不犯任何错误!
  • 当用户直接访问/protectedMedia/+ request.path 时会发生什么? NGINX 不会仍然将该文件提供给编外用户吗?
  • 我很难理解这个工作流程的概念,这篇文章对我有很大帮助!
  • @Emile 如果我理解 X-Sendfile 或 nginx X-Accel-Redirect 正确,它只是一个内部重定向到受保护的 url。因此,如果您调用/protectedMedia/+ request.path,您将无法访问,因为您没有通过服务器重定向。
  • 看来你可以用del response['Content-Type']完全删除标题标签
【解决方案2】:

这对我帮助很大,只是一个小的更新和修改:

urls.py:

re_path(r'^media/(?P<path>.*)', protectedMedia, name="protect_media")

views.py:

from urllib.parse import quote
from django.http import HttpResponse
from django.contrib.admin.views.decorators import staff_member_required


@staff_member_required
def protectedMedia(request, path):
    response = HttpResponse(status=200)
    response["Content-Type"] = ''
    response['X-Accel-Redirect'] = '/protectedMedia/' + quote(path)
    return response

我不得不将 nginx 配置更改为以下内容:

location /protectedMedia/ {
      internal;
      alias /home/{site-name}/;
}

注意事项:

  • 我更喜欢使用装饰器,因为它会自动重定向到登录页面(在设置中指定时)并设置“下一个”页面。
  • url() 得到 deprecated in Django 3.1 所以只需使用 re_path() 代替
  • 在 nginx 配置中使用别名而不是 root:我不想让“/protectedMedia/”出现在 url 中(而且它不起作用),另请参阅 nginx docs
  • 从 2021 年 6 月 14 日开始编辑:德语变音符号(äüö 等)在媒体路径中不起作用,因此我编辑了上述答案以包含 quote from urllib.parse

如果你仍然被困在某个地方,这给了我更多的背景信息:https://wellfire.co/learn/nginx-django-x-accel-redirects/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    • 2021-12-24
    • 1970-01-01
    • 2013-04-17
    • 1970-01-01
    相关资源
    最近更新 更多