Класс пользовательского хранилища-бэкенда не работает, как ожидалось, с s3, boto3 и django-storages

Я следую этому руководству здесь от Майкла Германа, пытаясь настроить хранилище s3 для моего проекта django, и я сталкиваюсь с некоторыми проблемами с самого начала руководства.

Во-первых, когда я попытался выполнить команду collectstatic, я получил эту ошибку:
botocore.exceptions.ClientError: An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
Я немного поискал, и, очевидно, вам нужно установить AWS_DEFAULT_ACL = None, и это помогло.

Теперь мои статические файлы загружались в ведро s3, когда я запускал collectstatic. Но когда я посещал веб-страницы, статические изображения и таблицы стилей не загружались, как ожидалось.
На этом этапе я перепробовал множество различных способов, но ни один из них не помог. Я набрал в браузере url объекта s3 и вот какую ошибку получил:

<Error>
    <Code>AccessDenied</Code>
    <Message>Access Denied</Message>
    <RequestId>419CX01JK1CAKYCS<RequestId>
<HostId>rB7y8qLl5a5G0I1LVx2lexUbJpcvnrdKIMZ3AVq69C81B3j4BRWZwLq5THNLINwSv6q5HFSAednN1yq2tRCQ6THuxEn+S/Kj</HostId>
</Error>

Следующее, что я сделал, - это сделал все объекты bucket общедоступными. В учебнике этого не сделано, и я не уверен, плохо это или нет? Кто-нибудь, пожалуйста, подскажите, так ли это.

Используя этот ответ, я установил Block all public access параметр на off, а также добавил политику Bucket, как показано ниже:

{
  "Version":"2012-10-17",
  "Statement":[
    {
      "Sid": "PublicRead",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::MY-BUCKET-NAME/*"
    }
  ]
}

Теперь мои статические изображения и таблицы стилей загружались отлично, но файлы шрифтов (.woff и другие статические файлы, которые должны быть загружены) выдавали в консоли такую ошибку:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://<bucket-name>.s3.amazonaws.com/static/unfold/fonts/inter/Inter-SemiBold.woff2. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 200.

Я передал эту ошибку в ChatGPT, и он попросил меня вставить это в CORS-настройки ведра:

[
  {
    "AllowedHeaders": [
      "*"
    ],
    "AllowedMethods": [
      "GET",
      "HEAD"
    ],
    "AllowedOrigins": [
      "*"
    ],
    "ExposeHeaders": [],
    "MaxAgeSeconds": 3000
  }
]

Добавление этого действительно помогло, и теперь все мои статические файлы загружались и получались из ведра s3, как и должно было быть.

После этого я выполнил оставшуюся часть руководства, чтобы настроить мои медиафайлы. Я добавил 3 класса бэкэнда хранения, наследующих от S3Boto3Storage

class StaticStorage(S3Boto3Storage):
    location = 'static'
    default_acl = 'public-read'

class PublicMediaStorage(S3Boto3Storage): 
    location = 'media' 
    default_acl = 'public-read' 
    file_overwrite = False

class PrivateMediaStorage(S3Boto3Storage): 
    location = 'private' 
    default_acl = 'private' 
    file_overwrite = False 
    custom_domain = False
# settings.py is like this

if USE_S3:
    # aws settings
    AWS_ACCESS_KEY_ID = os.getenv('AWS_ACCESS_KEY_ID')
    AWS_SECRET_ACCESS_KEY = os.getenv('AWS_SECRET_ACCESS_KEY')
    AWS_STORAGE_BUCKET_NAME = os.getenv('AWS_STORAGE_BUCKET_NAME')
    AWS_S3_REGION_NAME = os.getenv('AWS_S3_REGION_NAME')
    AWS_DEFAULT_ACL = None
    AWS_S3_CUSTOM_DOMAIN = f'{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com'
    AWS_S3_OBJECT_PARAMETERS = {'CacheControl': 'max-age=86400'}
    # s3 static settings
    STATIC_LOCATION = 'public-read'
    STATIC_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{STATIC_LOCATION}/'
    STATICFILES_STORAGE = 'myproject.storage_backends.StaticStorage'
    # s3 public media settings
    PUBLIC_MEDIA_LOCATION = 'media'
    MEDIA_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{PUBLIC_MEDIA_LOCATION}/'
    DEFAULT_FILE_STORAGE = 'myproject.storage_backends.PublicMediaStorage'
    # s3 private media settings
    PRIVATE_MEDIA_LOCATION = 'private'
    PRIVATE_FILE_STORAGE = 'myproject.storage_backends.PrivateMediaStorage'
else:
    STATIC_URL = 'static/'
    STATIC_ROOT = BASE_DIR / 'staticfiles'
    MEDIA_URL = 'media/'
    MEDIA_ROOT = BASE_DIR / 'mediafiles'
Медиафайлы

теперь загружаются в ведро и обслуживаются из него, но есть проблема с классом PrivateMediaStorage. Файлы, загруженные с помощью PublicMediaStorage, могут быть доступны любому пользователю с объектным url, как и ожидалось. Но по какой-то причине файлы, загруженные с помощью PrivateMediaStorage, также общедоступны по их url, и я не имею в виду подписанный url с AWSAccessKeyId, а просто объектный url вида: https://<bucket-name>.s3.eu-north-1.amazonaws.com/private/hello.txt

Я не уверен, какой шаг был сделан неправильно.

Вернуться на верх