繁体   English   中英

使用Django服务受保护的媒体文件

[英]Serve protected media files with django

我希望Django仅为登录用户提供一些媒体文件(例如,用户上传的文件)。 由于我的网站流量很低,我想我会保持简单,不要使用django-sendfile告诉Nginx什么时候提供文件。 相反,我将让Django / Gunicorn完成这项工作。 在我看来,这似乎要简单得多,对于人流量少的网站,这可能更安全。

但是,组织文件存储位置的最佳方法是什么? 媒体文件都存储在MEDIA_ROOT ,该目录由Nginx在生产中提供。 如果我将文件上传到MEDIA_ROOT/protected/我必须告诉Nginx不要在protected子目录中提供文件。

但这是个好主意吗? 对我来说,首先允许Nginx访问/media/然后保护子目录/media/protected/似乎有点冒险。 不使用MEDIA_ROOT的子目录存储受保护的文件会更好吗?

但是,如果我在模型中尝试类似以下操作:

upload_to='../protected/documents/%Y/%m/'

Django抱怨:

SuspiciousFileOperation at /admin/core/document/add/
The joined path (/home/me/projects/project/protected/documents/2016/09/test.file) is located outside of the base path component (/home/me/projects/project/media)

因此,我认为“离开” MEDIA_ROOT不是一个好MEDIA_ROOT

存储和提供受保护的媒体文件的最佳解决方案是什么?

我现在想出了以下解决方案:

我在Django设置中有此设置:

MEDIA_ROOT = "/projects/project/media/"
MEDIA_URL = "/media/

在我的模型中,我要么:

document = models.FileField(upload_to="public/documents")

要么

document = models.FileField(upload_to="protected/documents")

这样,我现在在媒体文件目录中有两个子目录“ public”和“ protected”。

Nginx或Django的开发服务器仅提供“ public”子目录中的文件。

对于Django开发服务器:

if os.environ["ENVIRONMENT_TYPE"] == 'development':
    urlpatterns += static(settings.MEDIA_URL + "public/", document_root=settings.MEDIA_ROOT + "public/")

对于Nginx(用于生产):

location /media/public/ {
    alias   /projects/project/media/public/;
}

当我要提供受保护的文档时,请执行以下操作:

在urls.py中:

url(r'^media/protected/documents/(?P<file>.*)$', core.views.serve_protected_document, name='serve_protected_document'),

在views.py中:

@login_required()
def serve_protected_document(request, file):
    document = get_object_or_404(ProtectedDocument, file="protected/documents/" + file)

    # Split the elements of the path
    path, file_name = os.path.split(file)

    response = FileResponse(document.file,)
    response["Content-Disposition"] = "attachment; filename=" + file_name

    return response

我将不胜感激! 有更好的方法来实现这一点吗?

直接从视图中提供媒体文件(可能是大文件)是不好的。 您可以使用nginx服务器中可用的sendfile扩展名; 一个示例nginx配置如下所示。

 location /projects/project/media/{
    # this path is not public
    internal;
    # absolute path
    alias /projects/project/media/;
 }

改变你的看法

@login_required
def serve_protected_document(request, file):
    document = get_object_or_404(ProtectedDocument, file="protected/documents/" + file)

    # Split the elements of the path
    path, file_name = os.path.split(file)

    response = HttpResponse()
    response["Content-Disposition"] = "attachment; filename=" + file_name
    # nginx uses this path to serve the file
    response["X-Accel-Redirect"] = document.name # path to file
    return response

链接:有关在nginx上配置sendfile扩展的更多详细信息,请参见此处

暂无
暂无

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

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