Как заставить Django сделать некоторые файлы общедоступными, а мультимедийные файлы — частными на AWS S3 (без ошибок 403)?

Я использую boto3 и django-storages в своем приложении Django для обслуживания файлов из AWS S3. Я бы хотел, чтобы мои статические файлы были общедоступными, а другие файлы — частными. У меня вроде работает, но не совсем. Мои статические файлы обслуживаются так, как если бы они были частными, с предварительно подписанным ключом. В моем файле шаблона, когда я использую:

<img src="{% static 'images/3d-house-nav-gray.png' %}">

вместо того, что я хочу

<img src="https://mybucket.s3.amazonaws.com/static/images/3d-house-nav-gray.png">

я собираюсь

<img id="home-img" src="https://mybucket.s3.amazonaws.com/static/images/3d-house-nav-gray.png?AWSAccessKeyId=AKIA1234564LQ7X4EGHK&amp;Signature=123456gIBTFlTQKCexLo3UJmoPs%3D&amp;Expires=1621693552">

На самом деле это работает, когда шаблоны рендерятся с сервера как часть HTTPResponse, но не когда подобное изображение просто включается как часть, скажем, файла .css. В таком случае я получу:

Failed to load resource: the server responded with a status of 403 (Forbidden)

(Я обнаружил, что если я скопирую и вставлю проблемную ссылку на изображение и заменю &amp; на &, тогда у меня будет доступ, еще одна загадка.)

Вот как я настроил AWS:

AWS_ACCESS_KEY_ID = os.environ['AWS_ACCESS_KEY_ID']
AWS_SECRET_ACCESS_KEY = os.environ['AWS_SECRET_ACCESS_KEY']
AWS_STORAGE_BUCKET_NAME = 'mybucket'
AWS_S3_OBJECT_PARAMETERS = {
    'CacheControl': 'max-age=86400',
}
AWS_DEFAULT_ACL = None
AWS_LOCATION = 'static'
STATICFILES_STORAGE = 'myapp.storage_backends.StaticStorage'
DEFAULT_FILE_STORAGE = 'myapp.storage_backends.MediaStorage'
AWS_S3_URL = 'https://%s.s3.amazonaws.com' % AWS_STORAGE_BUCKET_NAME
STATIC_DIRECTORY = '/static/'
MEDIA_DIRECTORY = '/media/'
STATIC_URL = AWS_S3_URL + STATIC_DIRECTORY
MEDIA_URL = AWS_S3_URL + MEDIA_DIRECTORY

Где myapp.storage_backends.py содержит:

from storages.backends.s3boto3 import S3Boto3Storage

class MediaStorage(S3Boto3Storage):
    location = 'media'
    file_overwrite = False

class StaticStorage(S3Boto3Storage):
    location = 'static'
    file_overwrite = True

А на AWS S3 моя политика ведра настроена так:

{
    "Version": "2012-10-17",
    "Id": "Policy1621539673651",
    "Statement": [
        {
            "Sid": "Stmt1621539665305",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::063896663644:user/mylogin"
            },
            "Action": [
                "s3:GetObject",
                "s3:GetObjectAcl",
                "s3:PutObject",
                "s3:PutObjectAcl"
            ],
            "Resource": "arn:aws:s3:::mybucket/*"
        },
        {
            "Sid": "Stmt1621539600741",
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::mybucket/static/*"
        }
    ]
}

Как я могу исправить это, чтобы сделать некоторые файлы (например, все в static/) неподписанными и общедоступными, а другие файлы подписанными и закрытыми?


person Dylan    schedule 22.05.2021    source источник


Ответы (1)


Если вы посмотрите на исходный код для django-storages вы увидите недокументированный класс с именем S3StaticStorage:

class S3StaticStorage(S3Boto3Storage):
    """Querystring auth must be disabled so that url() returns a consistent output."""
    querystring_auth = False

Подклассы из этого должны решить вашу проблему.

person Lord Elrond    schedule 22.05.2021
comment
Это важная подсказка. URL-адреса, созданные с помощью статического тега шаблона %, теперь не содержат дополнительных элементов подписи (например, ?AWSAccessKeyId=AKIA и т. д.), как я надеялся, но теперь все выдают ошибку 403, а не только ошибочные в файлах .css. Я думал, что второе утверждение в моей политике ведра сделает весь каталог static/ доступным для чтения. Что еще может отказать мне в разрешении? Спасибо за вашу помощь с этими вопросами новичка. - person Dylan; 22.05.2021