Класс пользовательского хранилища-бэкенда не работает, как ожидалось, с 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
Я не уверен, какой шаг был сделан неправильно.