Django - 使用自定义 login_required 装饰器保护 Apache 提供的媒体文件
Django - Protecting Media files served with Apache with custom login_required decorator
我使用 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,但不幸的是答案让我难以理解。
提前致谢!
当您提到 Apache 的媒体路径时,这些文件直接由 Apache(或 Nginx 或任何其他 Web 服务器)提供。这些请求甚至不会通过您的 Django 应用程序。因此,您无法控制这些请求或它们提供的数据。
一种方法是创建单独的 API 来为 static/media 文件提供服务。在那个 API 中,使用您对其他内容所做的相同验证。
更好的是,如果您分别有 AWS (Amazon Web Services) or GCP (Google Cloud Platform) account, store the static files on the S3 or Cloud Storage 并通过您的 API.
提供他们 URL 的文件
PS: 不要忘记从 Apache 配置中删除 media 路径。否则,Apache 将继续提供这些文件。
或者,如 which requires modification in both sever and application side. You need a way for your HTTP server to ask the application server if it is ok to serve a file to a specific user requesting it. You may achieve this using django-sendfile中所述,它使用X-SendFile机制。根据 django-sendfile 的 README:
This is a wrapper around web-server specific methods for sending files to web clients. This is useful when Django needs to check permissions associated files, but does not want to serve the actual bytes of the file itself. i.e. as serving large files is not what Django is made for.
要了解有关发送文件机制的更多信息,请阅读:Django - Understanding X-Sendfile
好的,基于@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 for Apache, or simply use Django Sendfile,它是刚才提到的模块的包装器。
我试了后者,可惜it has problems with file names that have non-ascii characters。由于我的目标是讲西班牙语的用户,我不得不求助于仅使用 Django 提供文件,至少现在是这样。
我在 post“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}),
)
在我的例子中,我将其编辑为以下内容,因为我的目录设置不同,并且我使用需要登录的中间件来确保在任何地方都需要登录 (Django: How can I apply the login_required decorator to my entire site (excluding static media)?:
urlpatterns = patterns('',
url(r'^media/(?P<path>.*)$', "django.views.static.serve", {'document_root': settings.MEDIA_ROOT}),
)
我使用 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,但不幸的是答案让我难以理解。
提前致谢!
当您提到 Apache 的媒体路径时,这些文件直接由 Apache(或 Nginx 或任何其他 Web 服务器)提供。这些请求甚至不会通过您的 Django 应用程序。因此,您无法控制这些请求或它们提供的数据。
一种方法是创建单独的 API 来为 static/media 文件提供服务。在那个 API 中,使用您对其他内容所做的相同验证。
更好的是,如果您分别有 AWS (Amazon Web Services) or GCP (Google Cloud Platform) account, store the static files on the S3 or Cloud Storage 并通过您的 API.
提供他们 URL 的文件PS: 不要忘记从 Apache 配置中删除 media 路径。否则,Apache 将继续提供这些文件。
或者,如
This is a wrapper around web-server specific methods for sending files to web clients. This is useful when Django needs to check permissions associated files, but does not want to serve the actual bytes of the file itself. i.e. as serving large files is not what Django is made for.
要了解有关发送文件机制的更多信息,请阅读:Django - Understanding X-Sendfile
好的,基于@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 for Apache, or simply use Django Sendfile,它是刚才提到的模块的包装器。
我试了后者,可惜it has problems with file names that have non-ascii characters。由于我的目标是讲西班牙语的用户,我不得不求助于仅使用 Django 提供文件,至少现在是这样。
我在 post“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}),
)
在我的例子中,我将其编辑为以下内容,因为我的目录设置不同,并且我使用需要登录的中间件来确保在任何地方都需要登录 (Django: How can I apply the login_required decorator to my entire site (excluding static media)?:
urlpatterns = patterns('',
url(r'^media/(?P<path>.*)$', "django.views.static.serve", {'document_root': settings.MEDIA_ROOT}),
)