将 Rails 表单发布到 s3 上传的策略和签名问题

Posted

技术标签:

【中文标题】将 Rails 表单发布到 s3 上传的策略和签名问题【英文标题】:Policy and Signature issues for a rails post form to s3 upload 【发布时间】:2012-12-12 08:34:17 【问题描述】:

我正在尝试关注 this "how-to"(从 POST 到 S3 存储桶),但我的策略和签名似乎失败了。

我不太确定我的政策和签名有误?但我知道我在评估我在助手中创建的方法时遇到了问题。我尝试将 Policy & 签名值转换为符号 <%= :S3_UPLOAD_SIGNATURE %> 并且我尝试过

我之前调用过辅助方法没有任何问题,所以我有点迷茫。

错误:

NameError in Proj_files#new

Showing /app/views/proj_files/new.html.erb where line #8 raised:

uninitialized constant ActionView::CompiledTemplates::S3_UPLOAD_POLICY
Extracted source (around line #8):

5:       <input type="hidden" name="AWSAccessKeyId" value= <%= ENV['AWS_ACCESS_KEY_ID'] %> > 
6:       <input type="hidden" name="acl" value="private"> 
7:       <input type="hidden" name="success_action_redirect" value="http://localhost/">
8:       <input type="hidden" name="policy" value= <%= S3_UPLOAD_POLICY %> >
9:       <input type="hidden" name="signature" value= <%= S3_UPLOAD_SIGNATURE %> >
10:       <input type="hidden" name="Content-Type" value="image/png">
11:       <!-- Include any additional input fields here -->

我有一个带有相应 new.html.erb 的 proj_files 控制器:

<form action="https://s3.amazonaws.com/MY_BUCKET" method="post" enctype="multipart/form-data">
  <input type="hidden" name="key" value="uploads/$filename">
  <input type="hidden" name="AWSAccessKeyId" value= <%= ENV['AWS_ACCESS_KEY_ID'] %> > 
  <input type="hidden" name="acl" value="private"> 
  <input type="hidden" name="success_action_redirect" value="http://localhost/">
  <input type="hidden" name="policy" value= <%= S3_UPLOAD_POLICY %> >
  <input type="hidden" name="signature" value= <%= S3_UPLOAD_SIGNATURE %> >
  <input type="hidden" name="Content-Type" value="image/png">
  <!-- Include any additional input fields here -->

  File to upload to S3: 
  <input name="file" type="file"> 
  <br> 
  <input type="submit" value="Upload File to S3"> 
</form> 

还有 proj_files_helper.rb:

module ProjFilesHelper

  def S3_UPLOAD_POLICY options = 
    options[:content_type] ||= ''
    options[:acl] ||= 'private'
    options[:max_file_size] ||= 500.megabyte
    options[:path] ||= ''

    Base64.encode64(
      "'expiration': '#10.hours.from_now.utc.strftime('%Y-%m-%dT%H:%M:%S.000Z')',
        'conditions': [
          'bucket': '#ENV['S3_BUCKET']',
          ['starts-with', '$key', ''],
          'acl': '#options[:acl]',
          'success_action_status': '201',
          ['content-length-range', 0, #options[:max_file_size]],
          ['starts-with','$Content-Type','']
        ]
    ").gsub(/\n|\r/, '')
  end


  def S3_UPLOAD_SIGNATURE options = 
    Base64.encode64(
      OpenSSL::HMAC.digest(
      OpenSSL::Digest::Digest.new('sha1'),
      ENV['AWS_SECRET_ACCESS_KEY'], s3_policy(options))).gsub("\n","")
  end

end

感谢观看!

更新: 我将方法名称更改为小写,这让我更进一步(我应该意识到这一点!)。

现在我收到 S3 错误:

<Error>
<Code>AccessDenied</Code>
<Message>
Invalid according to Policy: Policy Condition failed: ["eq", "$bucket", "MY_BUCKETS_NAME"]
</Message>

似乎我会寻找一个 ENV 变量 $bucket 错误引用...“MY_BUCKETS_NAME”确实显示了正确的存储桶名称...。如果有人可以提供任何帮助,让 Rails 发布表单到 S3并运行/指出我的错误,我将不胜感激。

谢谢

更新2 根据下面的评论,我将表单操作修改为“https://s3.amazonaws.com/MY_BUCKET”并收到此错误:

Invalid according to Policy: Policy Condition failed: ["eq", "$acl", "public-read"]

接近...谢谢!

更新3 我正在战斗!

我已修改策略并形成 ACL 以具有相同的一致值(私有或公共读取)。

下面的评论导致我将表单操作修改为:http://MY_BUCKET.s3.amazonaws.com/ 我收到此错误:

<Code>AccessDenied</Code>
<Message>
Invalid according to Policy: Policy Condition failed: ["eq", "$success_action_status", "201"]
</Message>

奇怪的是,当我转到 AWS S3 管理控制台并将文件上传到我的存储桶时,它告诉我链接是“http://s3.amazonaws.com/MY_BUCKET”形式的。我在 amazonaws 之前和之后添加了 MY_BUCKET,但仍然收到相同的错误...

我不确定哪里发生了错误配置...我将创建一个新存储桶并查看我是否设置错误...

谢谢!

现在可以使用了!!! 我修复了答案中的所有内容...但随后不得不再做一次更改...

我的表单有一个“success_action_redirect”字段,但我的策略有一个success_action_status!

政策和表单字段必须匹配!呵呵!

感谢所有帮助...是时候进一步调整它了!

【问题讨论】:

我猜你的存储桶名称不是:MY_BUCKETS_NAME 我用那个替换了错误消息存储桶名称引用...但错误确实引用了我的正确存储桶。 你的url中的bucket名称是否相同? https://YOUR_BUCKET_NAME.s3.amazonaws.com/ 不!它是...s3.amazonaws.com/MY_BUCKET_NAME 所以我的存储桶 URL 错误/在亚马逊上没有正确配置? 文件上传后就是这样,不是之前 【参考方案1】:

1/ 要上传文件,您必须使用此 URL "http://#bucket_name.s3.amazonaws.com/"。在documentation中有明确说明:

action 定义了处理请求的 URL;这必须设置为存储桶的 URL。例如,如果您的存储桶名称为“johnsmith”,则 URL 将为“http://johnsmith.s3.amazonaws.com/”

2/ 你必须有一致的策略,好像你在签名中设置了public-read,在表单中设置了private

【讨论】:

【参考方案2】:

我收到以下错误: 根据策略无效:策略条件失败:[\"eq\", \"$bucket\"

几个小时后,我了解到你不能有一个大写字母的桶。将存储桶更改为小写即可修复它。

【讨论】:

以上是关于将 Rails 表单发布到 s3 上传的策略和签名问题的主要内容,如果未能解决你的问题,请参考以下文章

Rails 6,无法将 s3_direct_upload gem 上传到 UPLOAD,查看工作正常

如何使用 axios 将文件上传到亚马逊 s3 存储桶?

通过使用 AWS-SDK PHP 生成的预签名帖子拒绝 AWS S3 上传访问

通过使用 AWS-SDK PHP 生成的预签名帖子拒绝 AWS S3 上传访问

NS-Vue/Rails 对 S3 存储桶的预签名 PUT 请求给出 403

基于浏览器的上传到 Amazon S3?