2

我使用 Apache 部署了一个 Django 应用程序,并使用装饰器在大多数视图中检查身份验证。

@custom_decorator
def myView(request):
    bla bla bla...

这不是 Django 附带的 @login_required 装饰器,但它几乎是一样的,除了它只允许来自某些组的用户访问。这按预期工作。

此外,我正在使用 Apache 提供媒体(用户上传的)文件,如下所示:

Alias /media /path/to/media
<Directory /path/to/media>
     Require all granted
</Directory

我可以很好地访问媒体文件,但问题是即使我没有登录也可以访问它们,只需手动输入 url,例如:

mySite/media/myFile.png

有没有办法限制对媒体文件的访问,希望使用自定义装饰器?

我偶然发现了一个类似的问题:How do you Require Login for Media Files in Django,但不幸的是,答案超出了我的想象。

提前致谢!

4

3 回答 3

1

当您提到 apache 的媒体路径时,这些文件直接由 Apache(或 Nginx 或任何其他 Web 服务器)提供。这些请求甚至不会通过您的 Django 应用程序。因此,您无法控制这些请求或它们提供的数据。

一种方法是创建单独的 API 来提供静态/媒体文件。在该 API 中,使用与其他内容相同的验证。

更好的是,如果您有AWS(亚马逊网络服务)GCP(谷歌云平台)帐户,请将静态文件分别存储在S3云存储上,并通过您的 API 提供文件的 URL。

PS:不要忘记从 Apache 配置中删除媒体路径。否则,Apache 将继续提供这些文件。


或者,正如Sarafeim 对Restricting access to private file downloads in Django的回答中提到的那样,这需要在服务器和应用程序端进行修改。您需要一种方法让您的 HTTP 服务器询问应用程序服务器是否可以将文件提供给请求它的特定用户。您可以使用使用 X-SendFile 机制的django-sendfile来实现这一点。根据django-sendfile 的 README

这是一个围绕 web 服务器特定方法的包装器,用于将文件发送到 web 客户端。当 Django 需要检查权限相关文件,但不想提供文件本身的实际字节时,这很有用。即服务大文件不是 Django 的目的。

要了解有关 sendfile 机制的更多信息,请阅读:Django - 了解 X-Sendfile

于 2016-11-19T20:53:02.997 回答
1

好的,所以基于@MoinuddinQuadri 答案和链接,似乎最简单的解决方案是使用常规 Django 视图提供文件,并应用所需的装饰器,如下所示:

@custom_decorator
viewFile(request, objectID):
    object = MyModel.object.get(id = objectID)
    return HttpResponse(object.file, content_type = "image/png")

(在我的例子中,我想提供一个与模型相关的 FileField,所以在视图中我传递了对象的 ID 而不是文件名)。

另外,我在 Apache conf 中注释掉了相应的代码:

### Alias /media /path/to/media
### <Directory /path/to/media>
###     Require all granted
###</Directory

我不得不更改一些模板以使用新视图而不是媒体文件的 URL,但现在它按预期工作,锁定了未登录的用户。

但是,这不再使用 Apache 来提供文件,它使用 Django 本身,根据 docs,这是无效的,不推荐使用。

理想情况下,您仍希望使用 Apache 提供文件,并仅使用视图来保护其访问权限,为此您可以使用Apache 的mod_xsendfile,或者简单地使用Django Sendfile,这是刚刚提到的模块的包装器。

我尝试了后者,但不幸的是,文件名有非 ascii 字符的问题。由于我的目标是说西班牙语的用户,因此我不得不仅使用 Django 提供文件,至少现在是这样。

于 2016-11-20T19:14:53.247 回答
1

我在帖子“ Django protected media files ”中使用了解决方案#1 。这里还描述了另外两种解决方案:“Unpredictable Urls”和“X-Sendfile”,但我描述的是我的选择。

正如@Sauvent 提到的,这会导致文件由 Django 提供,而不是由 Web 服务器(例如 Apache)提供。但是,如果您不处理大量流量或大文件,它会快速而简单。

基本上,将以下内容添加到您的 urls.py 中:

@login_required
def protected_serve(request, path, document_root=None, show_indexes=False):
    return serve(request, path, document_root, show_indexes)

urlpatterns = patterns('',
    url(r'^{}(?P<path>.*)$'.format(settings.MEDIA_URL[1:]), protected_serve, {'document_root': settings.MEDIA_ROOT}),
)

在我的情况下,我将其编辑为以下内容,因为我的目录设置不同,并且我使用 Login Required Middleware 来确保在任何地方都需要登录(Django:如何将 login_required 装饰器应用于我的整个站点(不包括静态媒体)?:

urlpatterns = patterns('',
    url(r'^media/(?P<path>.*)$', "django.views.static.serve", {'document_root': settings.MEDIA_ROOT}),
)
于 2018-12-02T08:06:20.933 回答