当前位置: 首页 > 知识库问答 >
问题:

NS Vue/Rails向S3发送预签名PUT请求,给出403

朱经武
2023-03-14

我的前端是Nativescript Vue应用程序。后端是Rails。我从rrails服务器获得一个预先签名的url,并使用该url在客户端发送put请求以进行图像上传。我在rails上生成了一个预先签名的url,如下所示:

def create_presigned_url
  filename = "#{self.id}.jpg"

  Aws.config[:credentials]=Aws::Credentials.new(
    "secret_id",
    "secret_key")
  s3 = Aws::S3::Resource.new(region: 'ap-southeast-1')

  bucket = 'bucket_name'
  obj = s3.bucket(bucket).object(filename)
  self.presigned_url = obj.presigned_url(:put, { acl: 'public-read' })
  self.update_column(:image_url, obj.public_url)
end

长话短说,上面的代码生成了一个预签名的url,我使用它来使用NativeScript-background-超文本传输协议插件在客户端执行放置请求:

var会话=bghttp。会话(“图像上传”)

UploadFile(session, file, url) {
    var request = {
      url: url,
      method: "PUT",
      headers: {
          "Content-Type": "application/octet-stream"
      },
      description: `Uploading ${file.substr(file.lastIndexOf("/") + 1)}` 
    };

    var task = session.uploadFile(file, request);
}

图像上传工作正常,它显示:

LOG from device Nexus 6P: 'currentBytes: 4096'
LOG from device Nexus 6P: 'totalBytes: 622121'
LOG from device Nexus 6P: 'eventName: progress'
LOG from device Nexus 6P: 'currentBytes: 323584'
LOG from device Nexus 6P: 'totalBytes: 622121'
LOG from device Nexus 6P: 'eventName: progress'
LOG from device Nexus 6P: 'currentBytes: 606208'
LOG from device Nexus 6P: 'eventName: progress'
LOG from device Nexus 6P: 'totalBytes: 622121'
LOG from device Nexus 6P: 'currentBytes: 622121'
LOG from device Nexus 6P: 'totalBytes: 622121'
LOG from device Nexus 6P: 'eventName: progress'
LOG from device Nexus 6P: 'eventName: error'
LOG from device Nexus 6P: 'eventName: 403'
LOG from device Nexus 6P: 'eventName: {}'

出现403错误,响应为:

<?xml version="1.0" encoding="UTF-8"?>
<Error>
    <Code>SignatureDoesNotMatch</Code>
    <Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>
...

我在谷歌上搜索了这个错误,发现上面的所有回复都是关于有错误的AWS密钥。然而,我已经确保我在rails上有正确的AWS凭据。我怀疑这可能与生成预签名url时的内容类型有关,但我不确定。我的bucket权限似乎是正确的,但我可能错过了一些东西。我已经制定了政策和CORS。

这是桶策略:

{
    "Version": "2012-10-17",
    "Id": "my-policy-id",
    "Statement": [
        {
            "Sid": "my-sid",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::my-id:user/my-user"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::my-bucket/*"
        }
    ]
}

这是CORS:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>DELETE</AllowedMethod>
    <AllowedMethod>HEAD</AllowedMethod>
    <ExposeHeader>ETag</ExposeHeader>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>

我的IAM用户也有必要的策略。

如有任何见解,将不胜感激。

编辑:我甚至删除了bucket策略并授予所有公众对bucket的访问权限,但我仍然看到403错误。错误是签名错误。

共有1个答案

沃念
2023-03-14

我必须改变self.presigned_url=obj.presigned_url(: put,{acl:'Public-read'})self.presigned_url=obj.presigned_url(: put,expires_in: 10*60,content_type:'Application/octet-stream')

而bucket ACL则为大家公开列表,私有写入。桶策略

{
    "Version": "2012-10-17",
    "Id": "policy_id",
    "Statement": [
        {
            "Sid": "my_statement_id",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::user_id:user/iam_user"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::my_bucket/*"
        },
        {
            "Sid": "PublicRead",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:GetObject",
                "s3:GetObjectVersion"
            ],
            "Resource": "arn:aws:s3:::my_bucket/*"
        }
    ]
}
 类似资料:
  • 我想将用户配置文件图片存储在S3桶中,但保留这些图片的私密性。为了做到这一点,我正在创建一个预先签名的网址,每当图像是必需的。然而,这每次都会创建一个独特的网址,这意味着浏览器永远不会缓存图像,最终我会在GET请求中支付更多。 下面是生成url的代码示例,我使用的是Laravel: 我认为,通过指定日期时间而不是时间单位,它将创建相同的url,但实际上会将剩余秒数添加到url,下面是一个示例: x

  • 我正试图用预签名的URL直接上传一个文件到S3 bucket,但在PUT请求上出现AccessDenied(403 Plibended)错误。 附注。忘了补充。我已经尝试添加和以及并且在本例中上载工作正常,但是如何限制上载的访问?它应该只适用于预签名的URL,对吗?

  • 我正在使用实现一个联系人应用程序。现在,我正试图通过发送以下格式的put请求来更新联系人 我将XML作为字符串发送,作为请求的主体。这是我的xmlString(请求主体) 我写了下面的代码来发送更新联系人的PUT请求。 当我试图在中发送请求时,联系人更新成功。但是当我试图运行上面的程序时,我得到了 400错误请求错误 我不知道我哪里出错了。任何帮助都将不胜感激!

  • 标题说明一切。这是我的代码; 我使用节点强大的文件。 成功上传后,url变量返回s3 url,类似以下内容; 下面是我的参数 我错过了什么?

  • 我正在尝试使用重定向规则设置静态web托管。在我的应用程序中,任何具有前缀api/(http://web.company.com/api)的请求都应该重定向到具有相同前缀(http://api.company.com/api)的另一个主机。我已按以下方式设置路由规则: 但请求没有被正确重定向。控制台中有两个不同的错误: XMLHttpRequest无法加载http://api.company.co

  • 问题内容: 我想知道是否可以将PUT,DELETE请求(实际上)发送java.net.HttpURLConnection到基于HTTP的URL。 我已经读了很多描述如何发送GET,POST,TRACE,OPTIONS请求的文章,但是我仍然没有找到成功执行PUT和DELETE请求的示例代码。 问题答案: 要执行HTTP PUT: 要执行HTTP删除: