如何在生产中保护 django 中的媒体文件?
How to secure media files in django in poduction?
我正在尝试制作一个项目并拥有一些只能由其所有者访问的媒体文件。
在生产中,媒体和静态文件由 apache(或 nginx,但我使用的是 apache)提供服务。
我正在寻找一些解决方案,但我无法申请。
在 djangosnippets 网站上,我找到了这段代码,
from mod_python import apache
from django.core.handlers.base import BaseHandler
from django.core.handlers.modpython import ModPythonRequest
class AccessHandler(BaseHandler):
def __call__(self, req):
from django.conf import settings
# set up middleware
if self._request_middleware is None:
self.load_middleware()
# populate the request object
request = ModPythonRequest(req)
# and apply the middleware to it
# actually only session and auth middleware would be needed here
for middleware_method in self._request_middleware:
middleware_method(request)
return request
def accesshandler(req):
os.environ.update(req.subprocess_env)
# check for PythonOptions
_str_to_bool = lambda s: s.lower() in ("1", "true", "on", "yes")
options = req.get_options()
permission_name = options.get("DjangoPermissionName", None)
staff_only = _str_to_bool(
options.get("DjangoRequireStaffStatus", "on")
)
superuser_only = _str_to_bool(
options.get("DjangoRequireSuperuserStatus", "off")
)
settings_module = options.get("DJANGO_SETTINGS_MODULE", None)
if settings_module:
os.environ["DJANGO_SETTINGS_MODULE"] = settings_module
request = AccessHandler()(req)
if request.user.is_authenticated():
if superuser_only and request.user.is_superuser:
return apache.OK
elif staff_only and request.user.is_staff:
return apache.OK
elif permission_name and request.user.has_perm(
permission_name
):
return apache.OK
return apache.HTTP_UNAUTHORIZED
但是我无法安装mod_python。 请先告诉我怎么做
我为 apache 更改了我的 .conf 文件,如下所示。
<VirtualHost *:80>
ServerName podcast.com
ServerAdmin srpatel980@gmail.com
DocumentRoot /home/username/Documents/secret_media
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
Alias /static /home/username/Documents/secret_media/static
<Directory /home/username/Documents/secret_media/static>
Require all granted
</Directory>
Alias /media /home/username/Documents/secret_media/media
<Directory /home/username/Documents/secret_media/media>
Require all granted
</Directory>
<Directory /home/username/Documents/secret_media/secret_media>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
WSGIScriptAlias / /home/username/Documents/secret_media/secret_media/wsgi.py
WSGIDaemonProcess secret_media python-path=/home/username/Documents/secret_media python-home=/home/username/Documents/secret_media/venv
WSGIProcessGroup secret_media
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule authz_user_module modules/mod_authz_user.so
<Location "/media/images">
PythonPath /home/username/Documents/secret_media
PythonOption DJANGO_SETTINGS_MODULE secret_media.settings
PythonAccessHandler secret_media.wsgi.py #this should point to accesshandler
SetHandler None
</Location>
</VirtualHost>
有些设置重复了,不知道为什么,求解释
一种方法是使用 so-called X-Sendfile。
简单来说:
- 用户请求 URL 获取受保护的文件(因此您需要将 public 和受保护的文件分开,然后将请求代理到 Django 以获取受保护的文件,或者直接提供文件来自 apache/nginx 如果它们是 public)
- Django 视图根据URL 决定要return 哪个文件,并检查用户权限等
- Django returns HTTP 响应 'X-Sendfile' header 设置为服务器的文件路径
- Web 服务器找到文件并return将其发送给请求者
nginx 和 apache 的设置会有所不同,根据我的发现,您需要为 apache 安装 mod_xsendfile,nginx 开箱即用。希望这对您有所帮助,如有需要,请提出任何其他问题。
X-Sendfile
我不知道你用上面的方法,但我一直在用mod_xsendfile做同样的事情。原理是什么:对 url 的请求由检查访问权限的视图处理...视图 returns 带有键“X-Sendfile”和文件的响应...这会触发 Apache on返回服务媒体文件的方式。
我只是给你看代码,没有测试语法....如果有不清楚的地方请问
阿帕奇 httpd.conf
LoadModule xsendfile_module modules/mod_xsendfile.so
在 Apache 中删除通常的“别名媒体...”
Apache httpd-vhosts.conf
<VirtualHost *:80>
# ... all your usual Django Config staff
# remove the usual alias /media/
# Alias /media/ d:/WEBSPACES/dieweltdahinter_project/media/
XSendFile on
XSendFilePath D:/your_path/media/
<Directory "D:/your_path/media">
Order Deny,Allow
Allow from all
</Directory>
</VirtualHost>
urls.py
urlpatterns = [
.....,
re_path(r'^media/(?P<folder>[A-Za-z0-9\-_]+)/(?P<filename>[A-Za-z0-9\-_]+).(?P<extension>[A-Za-z0-9]+)\/?$', app_views.media_xsendfile, name='media-xsendfile'),
.....
]
views.py
# add decorators to manage access
#
def media_xsendfile(request, folder='', filename=None, extension=None):
# add an kind of user check ....
# only server certain type of files
if extension in ('jpg', 'png', 'gif'):
response['Content-Type'] = 'image/'+extension
elif extension == 'mp3':
response['Content-Type'] = 'audio/mpeg'
else:
return
if not folder == '':
folder = '/'+folder+'/'
response = HttpResponse()
# this is the part of the response that Apache reacts upon:
response['X-Sendfile'] = smart_str(settings.MEDIA_ROOT + folder + filename + "." + extension)
# need to handover an absolute path to your file to Apache!!
return response
我正在尝试制作一个项目并拥有一些只能由其所有者访问的媒体文件。 在生产中,媒体和静态文件由 apache(或 nginx,但我使用的是 apache)提供服务。
我正在寻找一些解决方案,但我无法申请。
在 djangosnippets 网站上,我找到了这段代码,
from mod_python import apache
from django.core.handlers.base import BaseHandler
from django.core.handlers.modpython import ModPythonRequest
class AccessHandler(BaseHandler):
def __call__(self, req):
from django.conf import settings
# set up middleware
if self._request_middleware is None:
self.load_middleware()
# populate the request object
request = ModPythonRequest(req)
# and apply the middleware to it
# actually only session and auth middleware would be needed here
for middleware_method in self._request_middleware:
middleware_method(request)
return request
def accesshandler(req):
os.environ.update(req.subprocess_env)
# check for PythonOptions
_str_to_bool = lambda s: s.lower() in ("1", "true", "on", "yes")
options = req.get_options()
permission_name = options.get("DjangoPermissionName", None)
staff_only = _str_to_bool(
options.get("DjangoRequireStaffStatus", "on")
)
superuser_only = _str_to_bool(
options.get("DjangoRequireSuperuserStatus", "off")
)
settings_module = options.get("DJANGO_SETTINGS_MODULE", None)
if settings_module:
os.environ["DJANGO_SETTINGS_MODULE"] = settings_module
request = AccessHandler()(req)
if request.user.is_authenticated():
if superuser_only and request.user.is_superuser:
return apache.OK
elif staff_only and request.user.is_staff:
return apache.OK
elif permission_name and request.user.has_perm(
permission_name
):
return apache.OK
return apache.HTTP_UNAUTHORIZED
但是我无法安装mod_python。 请先告诉我怎么做
我为 apache 更改了我的 .conf 文件,如下所示。
<VirtualHost *:80>
ServerName podcast.com
ServerAdmin srpatel980@gmail.com
DocumentRoot /home/username/Documents/secret_media
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
Alias /static /home/username/Documents/secret_media/static
<Directory /home/username/Documents/secret_media/static>
Require all granted
</Directory>
Alias /media /home/username/Documents/secret_media/media
<Directory /home/username/Documents/secret_media/media>
Require all granted
</Directory>
<Directory /home/username/Documents/secret_media/secret_media>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
WSGIScriptAlias / /home/username/Documents/secret_media/secret_media/wsgi.py
WSGIDaemonProcess secret_media python-path=/home/username/Documents/secret_media python-home=/home/username/Documents/secret_media/venv
WSGIProcessGroup secret_media
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule authz_user_module modules/mod_authz_user.so
<Location "/media/images">
PythonPath /home/username/Documents/secret_media
PythonOption DJANGO_SETTINGS_MODULE secret_media.settings
PythonAccessHandler secret_media.wsgi.py #this should point to accesshandler
SetHandler None
</Location>
</VirtualHost>
有些设置重复了,不知道为什么,求解释
一种方法是使用 so-called X-Sendfile。 简单来说:
- 用户请求 URL 获取受保护的文件(因此您需要将 public 和受保护的文件分开,然后将请求代理到 Django 以获取受保护的文件,或者直接提供文件来自 apache/nginx 如果它们是 public)
- Django 视图根据URL 决定要return 哪个文件,并检查用户权限等
- Django returns HTTP 响应 'X-Sendfile' header 设置为服务器的文件路径
- Web 服务器找到文件并return将其发送给请求者
nginx 和 apache 的设置会有所不同,根据我的发现,您需要为 apache 安装 mod_xsendfile,nginx 开箱即用。希望这对您有所帮助,如有需要,请提出任何其他问题。
X-Sendfile
我不知道你用上面的方法,但我一直在用mod_xsendfile做同样的事情。原理是什么:对 url 的请求由检查访问权限的视图处理...视图 returns 带有键“X-Sendfile”和文件的响应...这会触发 Apache on返回服务媒体文件的方式。
我只是给你看代码,没有测试语法....如果有不清楚的地方请问
阿帕奇 httpd.conf
LoadModule xsendfile_module modules/mod_xsendfile.so
在 Apache 中删除通常的“别名媒体...”
Apache httpd-vhosts.conf
<VirtualHost *:80>
# ... all your usual Django Config staff
# remove the usual alias /media/
# Alias /media/ d:/WEBSPACES/dieweltdahinter_project/media/
XSendFile on
XSendFilePath D:/your_path/media/
<Directory "D:/your_path/media">
Order Deny,Allow
Allow from all
</Directory>
</VirtualHost>
urls.py
urlpatterns = [
.....,
re_path(r'^media/(?P<folder>[A-Za-z0-9\-_]+)/(?P<filename>[A-Za-z0-9\-_]+).(?P<extension>[A-Za-z0-9]+)\/?$', app_views.media_xsendfile, name='media-xsendfile'),
.....
]
views.py
# add decorators to manage access
#
def media_xsendfile(request, folder='', filename=None, extension=None):
# add an kind of user check ....
# only server certain type of files
if extension in ('jpg', 'png', 'gif'):
response['Content-Type'] = 'image/'+extension
elif extension == 'mp3':
response['Content-Type'] = 'audio/mpeg'
else:
return
if not folder == '':
folder = '/'+folder+'/'
response = HttpResponse()
# this is the part of the response that Apache reacts upon:
response['X-Sendfile'] = smart_str(settings.MEDIA_ROOT + folder + filename + "." + extension)
# need to handover an absolute path to your file to Apache!!
return response