简体   繁体   English

cordova-plugin-file-transfer:如何使用签名的URL将文件上传到S3?

[英]cordova-plugin-file-transfer: How do you upload a file to S3 using a signed URL?

I am able to upload to S3 using a file picker and regular XMLHttpRequest (which I was using to test the S3 setup), but cannot figure out how to do it successfully using the cordova file transfer plugin. 我可以使用文件选择器和常规XMLHttpRequest (用于测试S3设置)将其上传到S3,但无法弄清楚如何使用cordova文件传输插件成功完成此操作。

I believe it is either to do with the plugin not constructing the correct signable request, or not liking the local file uri given. 我认为这与该插件未构造正确的可签名请求有关,或者与该给定的本地文件uri不相关。 I have tried playing with every single parameter from headers to uri types, but the docs aren't much help, and the plugin source is bolognese. 我已经尝试过处理从标头到uri类型的每个参数,但是文档并没有太大帮助,并且插件来源是bolognese。

The string the request needs to sign match is like: 请求需要签名匹配的字符串如下:

PUT


1391784394
x-amz-acl:public-read
/the-app/317fdf654f9e3299f238d97d39f10fb1

Any ideas, or possibly a working code example? 有什么想法,或者可能是一个有效的代码示例?

A bit late, but I just spent a couple of days struggling with this so in case anybody else is having problems, this is how managed to upload an image using the javascript version of the AWS SDK to create the presigned URL. 有点晚了,但是我花了几天时间来解决这个问题,以防万一其他人遇到问题,这就是如何使用AWS开发工具包的javascript版本上载图像来创建预签名URL的方法。

The key to solving the problem is in the StringToSign element of the XML SignatureDoesNotMatch error that comes back from Amazon. 解决此问题的关键是从亚马逊返回的XML SignatureDoesNotMatch错误的StringToSign元素。 In my case it looked something like this: 就我而言,它看起来像这样:

<StringToSign>
    PUT\n\nmultipart/form-data; boundary=+++++org.apache.cordova.formBoundary\n1481366396\n/bucketName/fileName.jpg
</StringToSign>

When you use the aws-sdk to generate a presigned URL for upload to S3, internally it will build a string based on various elements of the request you want to make, then create an SHA1 hash of it using your AWS secret. 当您使用aws-sdk生成要上传到S3的预签名URL时,它将在内部基于您要发出的请求的各种元素构建一个字符串,然后使用您的AWS密钥为其创建SHA1哈希。 This hash is the signature that gets appended to the URL as a parameter, and what doesn't match when you get the SignatureDoesNotMatch error. 此哈希是作为参数附加到URL的签名,当您收到SignatureDoesNotMatch错误时,该SignatureDoesNotMatch不匹配。

So you've created your presigned URL, and passed it to cordova-plugin-file-transfer to make your HTTP request to upload a file. 因此,您已经创建了预签名的URL,并将其传递给cordova-plugin-file-transfer以发出HTTP请求来上传文件。 When that request hits Amazon's server, the server will itself build a string based on the request headers etc, hash it and compare that hash to the signature on the URL. 当该请求到达Amazon服务器时,服务器本身将根据请求标头等构建一个字符串,对其进行哈希处理并将该哈希与URL上的签名进行比较。 If the hashes don't match then it returns the dreaded... 如果哈希值不匹配,则返回可怕的...

The request signature we calculated does not match the signature you provided. Check your key and signing method.

The contents of the StringToSign element I mentioned above is the string that the server builds and hashes to compare against the signature on the presigned URL. 我上面提到的StringToSign元素的内容是服务器构建并哈希以与预签名URL上的签名进行比较的字符串。 So to avoid getting the error, you need to make sure that the string built by the aws-sdk is the same as the one built by the server. 因此,为避免出现错误,您需要确保aws-sdk构建的字符串与服务器构建的字符串相同。

After some digging about, I eventually found the code responsible for creating the string to hash in the aws-sdk . 经过一番探索,我最终找到了负责创建要哈希到aws-sdk的字符串的代码。 It is located (as of version 2.7.12) in: 它位于(自2.7.12版本起)位于:

node_modules/aws-sdk/lib/signers/s3.js

Down the bottom at line 168 there is a sign method: 在第168行底部,有一个sign方法:

sign: function sign(secret, string) { return AWS.util.crypto.hmac(secret, string, 'base64', 'sha1'); }

If you put a console.log in there, string is what you're after. 如果在其中放置console.log ,则string是您要使用的。 Once you make the string that gets passed into this method the same as the contents of StringToSign in the error message coming back from Amazon, the heavens will open and your files will flow effortlessly into your bucket. 一旦使传递到此方法的string与从亚马逊返回的错误消息中的StringToSign的内容相同,天堂就会打开,您的文件将毫不费力地流入您的存储桶。

On my server running node.js, I originally created my presigned URL like this: 在运行node.js的服务器上,我最初创建了这样的预签名URL:

var AWS = require('aws-sdk');

var s3 = new AWS.S3(options = {
    endpoint: 'https://s3-eu-west-1.amazonaws.com',
    accessKeyId: "ACCESS_KEY",
    secretAccessKey: "SECRET_KEY"
});

var params = {
    Bucket: 'bucketName',
    Key: imageName,
    Expires: 60
};

var signedUrl = s3.getSignedUrl('putObject', params);

//return signedUrl

This produced a signing string like this, similar to the OP's: 这产生了一个类似于OP的签名字符串:

PUT


1481366396
/bucketName/fileName.jpg

On the client side, I used this presigned URL with cordova-plugin-file-transfer like so (I'm using Ionic 2 so the plugin is wrapped in their native wrapper): 在客户端,我将此预签名URL与cordova-plugin-file-transfer使用(如下所示)(我正在使用Ionic 2,因此该插件被包装在其本地包装器中):

let success = (result: any) : void => { 
    console.log("upload success");
}

let failed = (err: any) : void => {
    let code = err.code;
    alert("upload error - " + code);
}

let ft = new Transfer();

var options = {
    fileName: filename,
    mimeType: 'image/jpeg',
    chunkedMode: false,
    httpMethod:'PUT',
    encodeURI: false,
};

ft.upload(localDataURI, presignedUrlFromServer, options, false)
.then((result: any) => {
    success(result);
}).catch((error: any) => {
    failed(error);
});

Running the code produced the signature doesn't match error, and the string in the <StringToSign> element looks like this: 运行生成的代码,签名不匹配错误,并且<StringToSign>元素中的字符串如下所示:

PUT

multipart/form-data; boundary=+++++org.apache.cordova.formBoundary
1481366396
/bucketName/fileName.jpg

So we can see that cordova-plugin-file-transfer has added in its own Content-Type header which has caused a discrepancy in the signing strings. 因此,我们可以看到cordova-plugin-file-transfer已在其自己的Content-Type标头中添加,这导致了签名字符串的差异。 In the docs relating to the options object that get passed into the upload method it says: 在与options对象相关的文档中 ,该文档传递到upload方法中,它说:

headers: A map of header name/header values. Use an array to specify more than one value. On iOS, FireOS, and Android, if a header named Content-Type is present, multipart form data will NOT be used. (Object)

so basically, if no Content-Type header is set it will default to multipart form data. 因此,基本上,如果未设置Content-Type标头,则默认为多部分表单数据。

Ok so now we know the cause of the problem, it's a pretty simple fix. 好的,现在我们知道了问题的原因,这是一个非常简单的修复。 On the server side I added a ContentType to the params object passed to the S3 getSignedUrl method: 在服务器端,我将ContentType添加到传递给S3 getSignedUrl方法的params对象中:

var params = {
    Bucket: 'bucketName',
    Key: imageName,
    Expires: 60,
    ContentType: 'image/jpeg' // <---- content type added here
};

and on the client added a headers object to the options passed to cordova-plugin-file-transfer 's upload method: 和客户端上添加一个headers反对options传递给cordova-plugin-file-transfer的上传方法:

var options = {
    fileName: filename,
    mimeType: 'image/jpeg',
    chunkedMode: false,
    httpMethod:'PUT',
    encodeURI: false,
    headers: { // <----- headers object added here
        'Content-Type': 'image/jpeg',
    }
};

and hey presto! 嘿,presto! The uploads now work as expected. 现在可以正常进行上传。

I run into such issues with this plugin 我在这个插件中遇到了这样的问题

The only working way I found to upload a file with a signature is the method of Christophe Coenraets : http://coenraets.org/blog/2013/09/how-to-upload-pictures-from-a-phonegap-app-to-amazon-s3/ 我发现上传带有签名的文件的唯一可行方法是Christophe Coenraets的方法: http ://coenraets.org/blog/2013/09/how-to-upload-pictures-from-a-phonegap-app- 到亚马逊-S3 /

With this method you will be able to upload your files using the cordova-plugin-file-transfer 使用此方法,您将可以使用cordova-plugin-file-transfer上载文件

First, I wanted to use the aws-sdk on my server to sign with getSignedUrl() It returns the signed link and you only have to upload to it. 首先,我想使用服务器上的aws-sdk与getSignedUrl()进行签名,它返回已签名的链接,而您只需要上传到该链接即可。

But, using the plugin it always end with 403 : signatures don't match 但是,使用插件时,它总是以403结尾:签名不匹配

It may be related to the content length parameter but I didn't found for now a working solution with aws-sdk and the plugin 它可能与content length参数有关,但是我暂时没有找到可使用aws-sdk和插件的解决方案

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使函数从cordova-plugin-file-transfer上传返回承诺 - How to make the function upload from cordova-plugin-file-transfer return a promise cordova-plugin-file-transfer插件在Windows 10 sencha touch store应用程序上不起作用 - cordova-plugin-file-transfer plugin not working on Windows 10 sencha touch store app 如何使用 angular 或 javascript 中的预签名 url 将文件上传到 S3 存储桶 - how to upload file to S3 bucket using pre-signed url in angular or javascript 如何通过 Node.js 中的预签名 URL 将文件上传到 AWS S3 存储桶 - How to Upload File to AWS S3 Bucket via pre signed URL in Node.js 从cordova文件传输插件上传文件到nodeJS服务器 - upload file from cordova file transfer plugin to nodeJS server 使用预先签名的POST URL将文件上载到AWS S3时设置随机文件名 - Set random file name when upload file to AWS S3 with pre-signed POST url 如何将文件上传到AWS中的预签名URL? - How do I upload a file to a pre-signed URL in AWS? 在cordova项目中,我正在使用文件传输插件上传个人资料照片,它始终返回Code 1错误? - In cordova project I am using file transfer plugin to upload a profile photo it always returns Code 1 error? 使用签名的上传URL从浏览器上传到S3失败 - Uploading to S3 from browser using signed upload URL fails 如何使用预签名的 URL 而不是凭证直接从浏览器上传到 AWS S3? - How to upload to AWS S3 directly from browser using a pre-signed URL instead of credentials?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM