可以使用django-storages和boto3上传到AWS S3,但无法查看(禁止访问403),无法理解原因

时间:2019-02-11 11:09:46

标签: django amazon-s3 boto3

我遵循了以下指南:https://simpleisbetterthancomplex.com/tutorial/2017/08/01/how-to-setup-amazon-s3-in-a-django-project.html

我已经成功设置了存储桶并将静态文件传输到Amazon S3。

但是,当我尝试加载S3文件时,收到403禁止消息。

这是我的settings.py文件中的内容:

# AWS s3 (image storage)

AWS_ACCESS_KEY_ID = 'XXX' # XXX replaced with the actual key
AWS_SECRET_ACCESS_KEY = 'YYY' # YYY replaced with the actual key

# sensitive data will be replaced with environment variables when page is public

AWS_STORAGE_BUCKET_NAME = 'diceart-static'
AWS_S3_CUSTOM_DOMAIN = 's3.eu-west-2.amazonaws.com/%s' % AWS_STORAGE_BUCKET_NAME
AWS_S3_OBJECT_PARAMETERS = {
'CacheControl': 'max-age=86400',
}
AWS_LOCATION = 'static'
AWS_DEFAULT_ACL = None
AWS_BUCKET_ACL = None

AWS_QUERYSTRING_AUTH = False

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static'),
]

STATIC_URL = 'https://%s/%s/' % (AWS_S3_CUSTOM_DOMAIN, AWS_LOCATION)

STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'

DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'

所以当我跑步

python manage.py collectstatic

一切正常!而且我可以看到所有上传到Amazon S3的文件。我还可以看到对此进行程序化访问的时间,所以我知道这一切都可行。

这是我希望提供S3文件的html模板文件的内容:

{% extends 'dice/base.html' %}
{% load crispy_forms_tags %}
{% load static %}

{% block content %}
  <form method="post" enctype="multipart/form-data">
    {% csrf_token %}
    {{ form|crispy }}
    {% if not uploaded_file_url %}
        <button type="submit" class="btn btn-success mt-2">Upload</button>
    {% endif %}
  </form>

  {% if uploaded_file_url %}
    <p>File uploaded at: <a href="{{ uploaded_file_url }}">{{ uploaded_file_url }}</a></p>
    <img src="{{ uploaded_file_url }}">
  {% endif %}

  <p><a href="{% url 'index' %}">Return to home</a></p>
  <p>Have a picture of a cat:</p>
  <p><img src="{% static 'cat.jpg' %}"></p>
{% endblock %}

关键是倒数第二行:

<p><img src="{% static 'cat.jpg' %}"></p>

上面的代码与用户文件上传有关,我暂时不使用S3。

现在,当页面加载时,它不会出现错误,并且相关行显示如下:

<img src="https://s3.eu-west-2.amazonaws.com/diceart-static/static/cat.jpg">

并对照我的S3存储桶检查它是否匹配:

https://s3.eu-west-2.amazonaws.com/diceart-static/static/cat.jpg

但是我收到403禁止错误并且没有图像加载。

这是我在Chrome开发人员工具网络标题中看到的内容:

Request URL: https://s3.eu-west-2.amazonaws.com/diceart-static/static/cat.jpg
Request Method: GET
Status Code: 403 Forbidden
Remote Address: 52.95.148.64:443
Referrer Policy: no-referrer-when-downgrade
Provisional headers are shown
Referer: https://mysubdomain.pythonanywhere.com/upload2/
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 
(KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36

引荐来源网址是加载图像的页面,该页面托管在Pythonanywhere上。

现在我不确定S3存储桶的网址。我在网上检查的所有地方似乎都有结构

https://diceart-static.s3.amazonaws.com

而不是我拥有的东西

https://s3.eu-west-2.amazonaws.com/diceart-static

我认为这可能只是对AWS网址结构的更改,而不是我的上传正常工作时出现的问题,但这也许值得一提。

因此,从本质上讲,我可以编程方式上传,但无法使用django-storages和boto3查看我的S3文件。我在这里想念什么?

请注意,存储桶不允许公共访问,但是我无法更改此设置,因为Amazon不允许我(?!)。我认为这并不重要,因为我在此处输入了凭据,我认为这些凭据将作为标头发送给我,以供访问。

2 个答案:

答案 0 :(得分:0)

在上述设置中, AWS_DEFAULT_ACL 设置为doc

  

如果设置为,则所有文件都将继承存储桶的ACL。

,S3的默认ACL为私有

您可以按照建议设置AWS_DEFAULT_ACL = None,然后通过继承S3Boto3Storage来编写自己的存储类:

#myapp/myfilestorage.py

from storages.backends.s3boto3 import S3Boto3Storage
from django.conf import settings

class StaticS3Storage(S3Boto3Storage):
   location = settings.AWS_STATIC_LOCATION
   default_acl = 'public-read'

那么您在我们的设置中也有此设置:

AWS_STATIC_LOCATION = 'static'

STATICFILES_STORAGE = 'myapp.myfilestorage.StaticS3Storage'

您也可以视情况编辑/复制 DEFAULT_FILE_STORAGE

答案 1 :(得分:0)

我认为该文章已过时,因此有点误导。 django-storages文档不是很好,但是经过反复试验,我认为您真正想要的设置是:

AWS_ACCESS_KEY_ID = '<enter key>'
AWS_SECRET_ACCESS_KEY = '<enter key>'
AWS_STORAGE_BUCKET_NAME = 'diceart-static'
AWS_S3_REGION_NAME = 'eu-west-2'
AWS_DEFAULT_ACL = None
AWS_S3_OBJECT_PARAMETERS = {
    'CacheControl': 'max-age=86400',
}
AWS_LOCATION = 'static'

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static'),
]

STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'

DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'

请注意,我已经从设置中删除了AWS_S3_CUSTOM_DOMAINSTATIC_URL。这些将由django-storages自动为您构建。

使用这些设置,您仍然应该能够将存储桶权限保留为不公开,并且由于使用了查询字符串身份验证,它仍然可以正常工作。


编辑

尽管上述方法可行,但我不确定这对于公共Web应用程序来说是“最佳实践”。如果您能够取消选中Block all public access框并将其关闭,则可以改用这些设置,而不会使用(或不需要)querystring auth。

# ... same as above
# Make default ACL publicly readable
AWS_DEFAULT_ACL = 'public-read'
# Turn off query auth, although not sure this is needed.
AWS_QUERYSTRING_AUTH = False
# ... same as above