【问题标题】:django-private-storage configuration in nginx and Dockernginx 和 Docker 中的 django-private-storage 配置
【发布时间】: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 中

我在实施过程中遗漏了什么吗?

提前致谢。

附加信息:

文件 -----------------------------------

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

【问题讨论】:

    标签: django docker nginx


    【解决方案1】:

    我也在这个库的测试阶段!

    我没有使用这些指示的行,这有助于加快大文件的上传速度。

    没有这些设置和 debug = False,一切正常。

    请参加考试。

    对不起,我不会说英语

    【讨论】:

    • "我没有使用这些行,这有助于加快大文件的上传速度。"你指的是哪几行?
    • 位置 /private-data/ { 内部; #
    【解决方案2】:

    我在 nginx 中的站点配置文件 mysite.conf

    server {
        listen 80;
        server_name mysite.com.br;
        return 301 https://mysite.com.br$request_uri;
    }
    
    server {
            listen 443 ssl http2;
            listen [::]:443 ssl http2;
    
            server_name mysite.com.br;
    
            location ~ ^/.well-known{
            root /var/www/myapp;
            }
    
            location / {
                  proxy_pass http://127.0.0.1:6010;  # My container is at port 3020
            }
    
        ssl_session_timeout 1d;
        ssl_session_cache shared:MozSSL:10m;  # about 40000 sessions
        ssl_session_tickets off;
    
        # Certificate free letsencrypt
        ssl_certificate /etc/letsencrypt/live/mysite.com.br/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/mysite.com.br/privkey.pem;
    
        ssl_protocols TLSv1.2 TLSv1.3;
    
        add_header Strict-Transport-Security "max-age=63072000" always;
    
    
        # OCSP stapling
        ssl_stapling on;
        ssl_stapling_verify on;
    }
    

    我的 django 的 setting.py

    MEDIA_ROOT = os.path.join(BASE_DIR, 'anexosapp')  # Folder for files private app
    MEDIA_URL = '/docs/'
    
    # Conf for django-private-storage
    INSTALLED_APPS += (
    'private_storage',
    )
    PRIVATE_STORAGE_ROOT = os.path.join(BASE_DIR, 'anexosapp/')
    PRIVATE_STORAGE_AUTH_FUNCTION = 'private_storage.permissions.allow_authenticated'  # allow user authenticated
    
    # settings for static server over whitenoise
    STATIC_URL = '/static/'
    STATICFILES_DIRS = [os.path.join(BASE_DIR, "static"), ]
    STATIC_ROOT = os.path.join(BASE_DIR, 'static')
    STATICFILES_STORAGE = 'whitenoise.storage.CompressedStaticFilesStorage'
    

    urls.py 应用主:

    urlpatterns += [
        path('private-media/', include(private_storage.urls)),
    ]
    

    文件访问 url 如下所示 https : //mysite.com.br/private-media/docs/namefile.pdf

    如果有人发现错误,改进设置的提示,请指出!谢谢

    【讨论】:

      【解决方案3】:

      我刚刚从 nginx.conf 位置删除了这样的私人媒体:

      upstream "my domain" {
          server web:8000;
      }
      
      server {
      
          listen 80;
      
          location / {
              proxy_pass http://"my domain";
              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 /privatefiles/ {
          #    alias /home/app/web/privatefiles/;
          #}
      
          # Error & Access logs
          error_log /home/app/logs/error.log error;
          access_log /home/app/logs/access.log;
      
          client_max_body_size 128m;
      
      }
      

      不要忘记设置DEBUG = False,那么它应该可以完美运行。每次我尝试在未登录的情况下访问私人媒体时,它都会将我重定向到登录页面。

      这是我的settings.py

      ...
      STATICFILES_DIRS = [
          os.path.join(BASE_DIR, "static")
      ]
      
      STATIC_URL = "/staticfiles/"
      
      STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")
      
      MEDIA_URL = "/mediafiles/"
      
      MEDIA_ROOT = os.path.join(BASE_DIR, "mediafiles")
      
      PRIVATE_STORAGE_ROOT = os.path.join(BASE_DIR, "privatefiles")
      
      PRIVATE_STORAGE_AUTH_FUNCTION = 'private_storage.permissions.allow_authenticated'
      ...
      

      还有我的主要urls.py

      from django.conf.urls.static import static
      from django.conf.urls import url
      from django.contrib import admin
      from django.urls import path, include
      from django.conf import settings
      
      import private_storage.urls <--- this is for private storage
      
      urlpatterns = [
          path('admin/', admin.site.urls),
          path('', include('core.urls')),
          path('rubric/', include('rubric.urls')),
          path('warehouse/', include('warehouse.urls')),
          path('preoffers/', include('preoffers.urls')),
          path('offers/', include('offers.urls')),
          url('^privatefiles/', include(private_storage.urls)) <--- this is for private storage
      ]
      
      if settings.DEBUG:
          urlpatterns += static(
              settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
      
          urlpatterns += static(
              settings.STATIC_URL, document_root=settings.STATIC_ROOT)
      

      【讨论】:

        【解决方案4】:

        'internal' 参数告诉 nginx 它不能从外部访问。

        我们访问应用程序,然后重定向到 nginx

        settings.py

        PRIVATE_STORAGE_ROOT = os.path.join(BASE_DIR, 'private-media')
        PRIVATE_STORAGE_AUTH_FUNCTION = 'private_storage.permissions.allow_staff'
        PRIVATE_STORAGE_SERVER = 'nginx'
        PRIVATE_STORAGE_INTERNAL_URL = '/private-x-accel-redirect/'
        

        nginx

        location /private-x-accel-redirect/ {
            internal;
            alias /var/www/private-media/;
        }
        

        【讨论】:

          猜你喜欢
          • 2019-01-08
          • 1970-01-01
          • 2016-04-11
          • 2023-04-09
          • 2021-02-02
          • 1970-01-01
          • 2014-10-16
          • 1970-01-01
          • 2020-08-02
          相关资源
          最近更新 更多