1

我可以使用django-storages&上传到 AWS S3,boto3但无法查看(403 Forbidden)。

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

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

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

这是我的 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 Forbidden 错误并且没有图像加载。

这是我在 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 存储桶的 url。我在网上查到的所有地方似乎都有这样的结构

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

而不是我所拥有的:

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

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

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

请注意,该存储桶不允许公开访问,但我无法更改此设置,因为亚马逊不允许我这样做(?!)。我认为这并不重要,因为我在这里输入了我的凭据,我认为这些凭据会作为标题发送给我访问权限。

4

2 回答 2

1

我认为那篇文章过时了,所以有点误导。 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_DOMAIN和。STATIC_URL这些将由 自动为您构建django-storages

使用这些设置,您应该仍然可以将您的存储桶权限设置为不公开,并且它应该仍然有效,因为它使用查询字符串身份验证。


编辑

虽然上述方法应该有效,但我不确定这是否是公共网络应用程序的“最佳实践”。如果您能够取消选中该Block all public access框并将其关闭,则可以改用这些设置,并且不会使用(或不需要)查询字符串身份验证。

# ... 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
于 2019-11-21T05:21:29.407 回答
1

From the above setting AWS_DEFAULT_ACL is set to None and the doc says

If set to None then all files will inherit the bucket’s ACL.

and the default ACL of S3 is private.

You can set AWS_DEFAULT_ACL = None as recommended and then write your own storage class by inheriting 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'

Then you we also have this in your settings:

AWS_STATIC_LOCATION = 'static'

STATICFILES_STORAGE = 'myapp.myfilestorage.StaticS3Storage'

you can also edit/duplicate it for DEFAULT_FILE_STORAGE as the case may be

于 2019-11-14T18:06:37.397 回答