允许用户将内容上传到s3

我有一个在BUCKET_REGION区域名为BUCKET的S3存储桶。 我试图让我的网站和移动应用程序的用户上传图像文件到这些桶,只要他们满足一定的限制基于Content-TypeContent-Length (即,我想只允许jpegs小于3mbs是上传)。 一旦上传,文件应公开访问。

基于对AWS文档进行的相当广泛的挖掘,我假定在我的前端应用程序中该过程应该看起来像这样:

 const a = await axios.post('my-api.com/get_s3_id'); const b = await axios.put(`https://{BUCKET}.amazonaws.com/{a.id}`, { // ?? headersForAuth: a.headersFromAuth, file: myFileFromSomewhere // ie HTML5 File() object }); // now can do things like <img src={`https://{BUCKET}.amazonaws.com/{a.id}`} /> // UNLESS the file is over 3mb or not an image/jpeg, in which case I want it to be throwing errors 

在我的后端API,我会做类似的事情

 import aws from 'aws-sdk'; import uuid from 'uuid'; app.post('/get_s3_id', (req, res, next) => { // do some validation of request (ie checking user Ids) const s3 = new aws.S3({region: BUCKET_REGION}); const id = uuid.v4(); // TODO do something with s3 to make it possible for anyone to upload pictures under 3mbs that have the s3 key === id res.json({id, additionalAWSHeaders}); }); 

我不确定的是我应该看到什么S3方法。


以下是一些不起作用的东西:

  • 我已经看到很多提到的(一个非常古老的)可用s3.getSignedUrl('putObject', ...)访问的API。 但是,这似乎并不支持可靠地设置一个ContentLength – 至less已经。 (请参阅https://stackoverflow.com/a/28699269/251162 。)

  • 我也看到了一个更接近于正在使用的form-data API的HTTP POST ,也是非常古老的例子。 我想如果没有其他select,这可能会完成,但我担心它不再是“正确的”做事的方式 – 此外,似乎做了大量的手动encryption等,而不是使用官方节点SDK。 (请参阅https://stackoverflow.com/a/28638155/251162 。)

我认为在直接发布到S3的情况下可能会更好,跳过你的后端服务器。

您可以做的是定义一个策略,明确指定可以上传到哪里的内容,然后使用AWS秘密访问密钥(使用AWS sig v4,可以使用此策略生成策略) 对此策略进行签名。

策略和签名的示例用法(如果在AWS文档中可查看)

为了您的使用,您可以指定如下条件:

 conditions: [ ['content-length-range, 0, '3000000'], ['starts-with', '$Content-Type', 'image/'] ] 

这将限制上传到3Mb,并将Content-Type只限于以image/

此外,您只需要为策略生成一次签名(或者只要发生更改),这意味着您不需要向服务器请求获取有效策略,只需将其硬编码到JS中。 当/如果你需要更新只重新生成策略和签名,然后更新JS文件。

编辑:没有一种方法通过SDK来做到这一点,因为它是从网页上的表单直接发布的方式,即可以使用没有JavaScript。

编辑2:如何使用标准NodeJS包签名策略的完整示例:

 import crypto from 'crypto'; const AWS_ACCESS_KEY_ID = process.env.AWS_ACCESS_KEY_ID; const AWS_SECRET_ACCESS_KEY = process.env.AWS_SECRET_ACCESS_KEY; const ISO_DATE = '20190728T000000Z'; const DATE = '20161201'; const REGION = process.env.AWS_DEFAULT_REGION || 'eu-west-1'; const SERVICE = 's3'; const BUCKET = 'your_bucket'; if (!AWS_ACCESS_KEY_ID || !AWS_SECRET_ACCESS_KEY) { throw new Error('AWS credentials are incorrect'); } const hmac = (key, string, encoding) => { return crypto.createHmac("sha256", key).update(string, "utf8").digest(encoding); }; const policy = { expiration: '2022-01-01T00:00:00Z', conditions: [ { bucket: BUCKET, }, ['starts-with', '$key', 'logs'], ['content-length-range', '0', '10485760'], { 'x-amz-date': ISO_DATE, }, { 'x-amz-algorithm': 'AWS4-HMAC-SHA256' }, { 'x-amz-credential': `${AWS_ACCESS_KEY_ID}/${DATE}/${REGION}/${SERVICE}/aws4_request` }, { 'acl': 'private' } ] }; function aws4_sign(secret, date, region, service, string_to_sign) { const date_key = hmac("AWS4" + secret, date); const region_key = hmac(date_key, region); const service_key = hmac(region_key, service); const signing_key = hmac(service_key, "aws4_request"); const signature = hmac(signing_key, string_to_sign, "hex"); return signature; } const b64 = new Buffer(JSON.stringify(policy)).toString('base64').toString(); console.log(`b64 policy: \n${b64}`); const signature = aws4_sign(AWS_SECRET_ACCESS_KEY, DATE, REGION, SERVICE, b64); console.log(`signature: \n${signature}\n`); 

你的服务器就像一个代理,也负责授权,validation等。一些代码片段:

  upload(config, file, cb) { const fileType = // pass with request or generate or let empty const key = `${uuid.v4()}${fileType}`; // generate file name: const s3 = new AWS.S3(); const s3Params = { Bucket: config.s3_bucket, Key: key, Body: file.buffer }; s3.putObject(s3Params, cb); } 

然后您可以将密钥发送给客户端并提供进一步的访问权限。

这是我知道我们在我们的项目,所以我会告诉你的代码的一部分:

你首先需要发布到你自己的服务器来获取上传的信誉,从那里你将返回从客户端上传到S3的参数。

这些是你发送到aws s3服务的参数,你需要存储桶,上传path和文件

  let params = { Bucket: s3_bucket, Key: upload_path, Body: file_itself }; 

这是我的实际上传到s3的代码

 config.credentials = new AWS.Credentials(credentials.accessKeyId, credentials.secretAccessKey, credentials.sessionToken); let s3 = new S3(config); return s3.upload(params, options).on("httpUploadProgress", handleProgress); 

所有这些凭证项目当然是从后端获得的。

在后端,您需要生成一个定时的,预先登记的URL,并将该URL发送到客户端以访问S3对象。 根据您的后端实现技术,您可以使用AWS CLI或SDK(例如Java,.Net,Ruby或Go)。

请参阅CLI文档和SDK文档以及更多SDK

链接生成中不直接支持内容大小限制。 但链接就在那里中继AWS用户拥有的访问权限。

要使用策略限制上传文件大小,您必须在存储段上创buildCORS策略,并使用HTTP POST进行上传。 请看这个链接 。

您需要熟悉Amazon Cognito,特别是身份validation池。

通过使用Amazon Cognito Sync,您可以跨客户端平台,设备和操作系统检索数据,这样,如果用户在手机上开始使用您的应用,然后切换到平板电脑,则该用户仍然可以使用持久的应用信息。

在这里阅读更多: Cognito身份池

一旦你创build了新的标识池,你可以在使用S3 JavaScript SDK的时候参考它,这将允许你上传内容,将任何凭证公开给客户端。

示例: 上传到S3

请仔细阅读所有内容,特别是“configurationSDK”部分。

你的拼图的第二部分 – validation。

我会去执行客户端validation(如果可能的话),以避免在发生错误之前的networking延迟。 如果您select在S3或AWS Lambda上实施validation,则需要等待文件达到AWS的等待时间 – networking延迟。