Django - 使用自定义login_required装饰器为Apache提供的保护媒体文件

问题描述:

我使用Apache部署了Django应用程序,并使用装饰器检查大多数视图中的身份验证。Django - 使用自定义login_required装饰器为Apache提供的保护媒体文件

@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 

我可以访问媒体文件就好了,但问题是,我可以,如果我连他们访问“M没有登录,只需通过手动输入网址,例如:

mySite/media/myFile.png 

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

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

在此先感谢!

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

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

更妙的是,如果你有AWS (Amazon Web Services)GCP (Google Cloud Platform)帐户,存放在S3Cloud Storage静态文件分别通过您的API服务于他们的文件的URL。

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


或者,如Sarafeim's answer to Restricting access to private file downloads in Django中所述,其需要在服务器端和应用端都进行修改。您需要一种方法让HTTP服务器询问应用程序服务器是否可以将文件提供给请求的特定用户。您可以使用使用X-SendFile机制的django-sendfile来实现此目的。由于每Django的sendfile的自述

这是围绕Web服务器的具体方法的包装将文档发送给Web客户端。当Django需要检查权限关联文件,但不想提供文件本身的实际字节时,这非常有用。即服务大文件不是Django的目的。

要了解更多关于sendfile的机制,请阅读:Django - Understanding X-Sendfile

+1

感谢您的有用答案,我注意到您编辑它以添加更多信息,例如五次,哈。我用解决方案编辑了原文,谢谢! – Sauvent

+1

@Sauvent:将这些信息添加为原始帖子的答案会更好。问题是问题的地方,答案是回答:)另外,感谢您回来并与我们分享您的所作所为。对未来面临此问题的人有所帮助。 –

+0

我编辑了这个问题,回到它原来的样子,并分开发布答案,谢谢大家的支持:) – Sauvent

好了,所以基于@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本身,其中according to the docs,是不合适的,不建议。

理想情况下,您希望仍然使用Apache提供文件并仅使用该视图来保护其访问,并且您可以使用mod_xsendfile用于Apache,或者仅使用Django Sendfile,这是上述模块的包装。

我试过后者,但不幸it has problems with file names that have non-ascii characters。由于我的目标是使用西班牙语的用户,所以我不得不采取仅仅通过Django提供文件服务,至少现在是如此。