【发布时间】:2021-08-13 22:59:38
【问题描述】:
我正在尝试使用 django-private-storage 包来保护模型的文件不被访问 或由非文件所有者的用户下载。
我能够在开发中成功地做到这一点(使用 python manage.py runserver)
在开发中,我使用的是通过 docker 配置的 nginx。
我可以使用 FileField 和 PrivateFileField 创建对象。我的问题是访问与 PrivateFileField 关联的 url。
媒体文件按预期提供(例如,当我访问 FileField 的 url 时),但是当我访问 PrivateFileField 的 url 时,我从 nginx 收到“404 Not Found”错误。
我的预感是服务器响应没有正确配置为具有“X-Accel-Redirect”数据, 从而将响应处理为非内部响应。
如果我删除“内部”行在我的私有数据位置的 nginx.conf 中,提供 PrivateFile 正确,尽管现在它不是私有的。
location /private-data/ {
internal; #<------ the PrivateFile can be accessed if this line is removed
alias /home/app/web/private-data/;
}
另外,我确定私有文件保存在 /home/app/web/private-data 中
我在实施过程中遗漏了什么吗?
提前致谢。
附加信息:
- nginx版本:1.17.4
- django-private-storage 版本:2.2.2
- 我的生产设置如下: https://testdriven.io/blog/dockerizing-django-with-postgres-gunicorn-and-nginx/
文件 -----------------------------------
docker-compose.prod.yml
version: '3.7'
services:
web:
build:
context: ./web_app
dockerfile: Dockerfile.prod
command: gunicorn notify_django_project.wsgi:application --bind 0.0.0.0:8000
volumes:
- static_volume:/home/app/web/staticfiles
- media_volume:/home/app/web/mediafiles
- private_volume:/home/app/web/private-data
expose:
- 8000
env_file:
- ./.env.prod
depends_on:
- db
db:
image: postgres:12.0-alpine
volumes:
- postgres_data:/var/lib/postgresql/data/
env_file:
- ./.env.prod.db
nginx:
build: ./nginx
volumes:
- static_volume:/home/app/web/staticfiles
- media_volume:/home/app/web/mediafiles
- private_volume:/home/app/web/private-data
ports:
- 1337:80
depends_on:
- web
volumes:
postgres_data:
static_volume:
media_volume:
private_volume:
nginx.conf
upstream django_project {
server web:8000;
}
server {
listen 80;
location / {
proxy_pass http://django_project;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
location /staticfiles/ {
alias /home/app/web/staticfiles/;
}
location /mediafiles/ {
alias /home/app/web/mediafiles/;
}
location /private-data/ {
internal;
alias /home/app/web/private-data/;
}
}
settings.py
INSTALLED_APPS = [
...
'private_storage',
....
]
PRIVATE_STORAGE_ROOT = os.path.join(BASE_DIR, "private-data")
PRIVATE_STORAGE_AUTH_FUNCTION = 'private_storage.permissions.allow_authenticated'
PRIVATE_STORAGE_INTERNAL_URL = '/private-data/'
PRIVATE_STORAGE_SERVER = 'nginx'
models.py
class Message(models.Model):
id = models.UUIDField(
primary_key=True,
default=uuid.uuid4,
editable=False)
subject = models.CharField(max_length=255)
attachment = models.FileField(upload_to=get_attachment_save_path, null=True, blank=True)
private_attachment = PrivateFileField(upload_subfolder=get_private_attachment_save_path, null=True, blank=True)
urls.py
urlpatterns = [
...
path('private-data/<str:code>/<int:year>/<str:subdir>/<uuid:pk>/<str:filename>', DownloadPrivateFileView.as_view(), name="file_download"),
url('^private-data/', include(private_storage.urls)),
...
]
views.py
@method_decorator(login_required, name='dispatch')
class DownloadPrivateFileView(PrivateStorageDetailView):
model = Message
model_file_field = 'private_attachment'
def can_access_file(self, private_file):
# When the object can be accessed, the file may be downloaded.
# This overrides PRIVATE_STORAGE_AUTH_FUNCTION
# grant_access checks private_file ownership
grant_access = grant_note_access(private_file.request, message=self.get_object())
return grant_access
【问题讨论】: