如何从浏览器中使用的凭据pre-标识的URL,而不是上传到AWS的S3直接? [英] How to upload to AWS S3 directly from browser using a pre-signed URL instead of credentials?

查看:224
本文介绍了如何从浏览器中使用的凭据pre-标识的URL,而不是上传到AWS的S3直接?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们想使用JavaScript AWS SDK文件上传到S3,但不使用凭证都没有。 使用上传作品的凭据,但我们不能生成一个AWS IAM用户对我们的每一个应用程序的用户(或者我们应该?)

因此​​,类似于使用GET,我们希望在服务器生成pre-标识的URL,将其发送给浏览器,让浏览器上传到该网址。

然而,存在关于如何实现这一点没有实施例。 另外,如果不设置的凭证,甚至在使载至S3请求,使用SDK误差

  code:CredentialsError
消息:没有凭据来加载
 

在JS SDK文档提到这一点,所以现在看来​​,这将是可能的:

  pre-签署putObject(异步)
VAR PARAMS = {斗:'斗',关键:关键};
    s3.getSignedUrl('putObject',参数,可以功能(ERR,网址){
      的console.log(网址,网址);
});
 

解决方案

沉静的老问题,但它确实帮助我一点得到它终于完成了。 我的解决方案是基于PHP和JavaScript与jQuery。

我的整个解决方案很好地包裹在 https://github.com/JoernBerkefeld/s3SignedUpload 但这里的要点:

api.php:

 < PHP
require_once'/server/path/to/aws-autoloader.php;
使用AWS \共同\ AWS;

$桶=我斗;
$ CONFIG =路径到IAM-凭证文件相对到root.php

功能getSignedUrl($文件名,$ MIME){
    $ S3 = AWS ::工厂($ CONFIG) - >获得(S3);
    如果(!$文件名){
        返回$这个 - >错误(文件名失踪');
    }
    如果(!$ MIME){
        返回$这个 - >错误(MIME类型缺失');
    }
    $ final_filename = $这个 - > get_file_name($文件名);
    尝试 {
        $ signedUrl = $ S3-> getCommand('PutObject',阵列(
            '斗'=> $斗,
            '关键'=> $这个 - >文件夹。 $ final_filename,
            '的ContentType'=> $哑剧,
            身体=> '',
            ContentMD5'=>假
        )) -  GT;创建presignedUrl('+ 30分钟);
    }赶上(S3Exception $ E){
        回声$ E->的getMessage()。 \ N的;
    }
    $ signedUrl ='和;的Content-Type ='。urlen code($ MIME);
    返回$ signedUrl;
}


回声getSignedUrl($ _ GET ['名'],$ _ GET ['MIMETYPE']);
 

请务必添加用户身份验证以您的api.php。否则大家谁知道的路径,该文件可以上传文件到你的水桶。

credentials.inc.php:

 < PHP
返回数组(
    包括'=>阵列('_ AWS),
    '服务'=>阵列(
        default_settings'=>阵列(
            '参数'=>阵列(
                '键'=> MY-ACCESS-KEY,
                秘密=> MY-朱鸿,
                '区域'=> 欧盟 - 西-1//设置为您的区域
            )
        )
    )
);
 

client.js:

  $(输入[type = file])。的onchange =功能(){
    对于(var文件,I = 0; I< this.files.length;我++){
        文件= this.files [I]
        $阿贾克斯({
            网址:S3 presignedApiUri,
            数据:'文件='+ file.name +'和;哑剧='+ file.type,
            键入:GET,
            数据类型:JSON,
            缓存:假的,
        })
        .done(函数(S3 presignedUrl){
            $阿贾克斯({
                网址:S3 presignedUrl,
                键入:PUT
                数据:文件,
                数据类型:文本,
                缓存:假的,
                的contentType:file.type,
                过程数据:假的
            })
            .done(函数(){
                console.info('是',S3 presignedUrl.split()[0] .substr(6)'?');
            }
            .fail(函数(){
                console.error(该死...);
            }
        })
    }
};
 

S3 CORS设置(PUT和放大器;实际所需的功能,但不能直接启用选项...):

 < XML版本=1.0编码=UTF-8&GT?;
< CORSConfiguration的xmlns =htt​​p://s3.amazonaws.com/doc/2006-03-01/>
    < CORSRule>
        < AllowedOrigin> *< / AllowedOrigin>
        < AllowedMethod> GET< / AllowedMethod>
        < AllowedMethod> POST< / AllowedMethod>
        < AllowedMethod> PUT< / AllowedMethod>
        &其中; AllowedMethod> HEAD&所述; / AllowedMethod>
        < AllowedMethod>删除< / AllowedMethod>
        < MaxAgeSeconds> 3000< / MaxAgeSeconds>
        < AllowedHeader> *< / AllowedHeader>
    < / CORSRule>
< / CORSConfiguration>
 

We'd like to use Javascript AWS SDK to upload files to S3, but without using credentials at all. Uploading using credentials works, but we cannot generate an AWS IAM user for each of our app users (or should we?)

Therefore, similar to using GET, we'd like the server to generate a pre-signed URL, send it to browser, and have the browser upload to that URL.

However, there are no examples on how to accomplish this. Also, if not setting a credential, even before making the upload to S3 request, the SDK errors with

code: "CredentialsError"
message: "No credentials to load"

The JS SDK docs mention this, so it seems it would be possible:

Pre-signing a putObject (asynchronously)
var params = {Bucket: 'bucket', Key: 'key'};
    s3.getSignedUrl('putObject', params, function (err, url) {
      console.log('The URL is', url);
});

解决方案

Quiet the old question but it did help me a bit to get it finally done. My solution is based on PHP and JavaScript with jQuery.

I have the entire solution nicely wrapped at https://github.com/JoernBerkefeld/s3SignedUpload but here are the essentials:

api.php:

<?php
require_once '/server/path/to/aws-autoloader.php';
use Aws\Common\Aws;

$BUCKET = "my-bucket";
$CONFIG = "path-to-iam-credentials-file-relative-to-root.php"

function getSignedUrl($filename, $mime) {
    $S3 = Aws::factory( $CONFIG )->get('S3');
    if(!$filename) {
        return $this->error('filename missing');
    }
    if(!$mime) {
        return $this->error('mime-type missing');
    }
    $final_filename = $this->get_file_name($filename);
    try {
        $signedUrl = $S3->getCommand('PutObject', array(
            'Bucket' => $BUCKET,
            'Key' => $this->folder . $final_filename,
            'ContentType' => $mime,
            'Body'        => '',
            'ContentMD5'  => false
        ))->createPresignedUrl('+30 minutes');
    } catch (S3Exception $e) {
        echo $e->getMessage() . "\n";
    }
    $signedUrl .= '&Content-Type='.urlencode($mime);
    return $signedUrl;
}


echo getSignedUrl($_GET['filename'],$_GET['mimetype']);

please make sure to add user authentication to your api.php. Else everyone who knows the path to that file could upload files to your bucket.

credentials.inc.php:

<?php
return array(
    'includes' => array('_aws'),
    'services' => array(
        'default_settings' => array(
            'params' => array(
                'key'    => 'MY-ACCESS-KEY',
                'secret' => 'MY-SECRECT',
                'region'  => 'eu-west-1' // set to your region
            )
        )
    )
);

client.js:

$("input[type=file]").onchange = function () {
    for (var file, i = 0; i < this.files.length; i++) {
        file = this.files[i];
        $.ajax({
            url : s3presignedApiUri,
            data: 'file='+ file.name + '&mime=' + file.type,
            type : "GET",
            dataType : "json",
            cache : false,
        })
        .done(function(s3presignedUrl) {
            $.ajax({
                url : s3presignedUrl,
                type : "PUT",
                data : file,
                dataType : "text",
                cache : false,
                contentType : file.type,
                processData : false
            })
            .done(function(){
                console.info('YEAH', s3presignedUrl.split('?')[0].substr(6));
            }
            .fail(function(){
                console.error('damn...');
            }
        })
    }
};

s3 cors settings (PUT & OPTIONS are actually needed, but cannot enable OPTIONS directly...):

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

这篇关于如何从浏览器中使用的凭据pre-标识的URL,而不是上传到AWS的S3直接?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆