Laravel保护Amazon S3存储桶文件 [英] Laravel secure Amazon s3 bucket files

查看:82
本文介绍了Laravel保护Amazon S3存储桶文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Amazon s3,但是在这里我面临两个问题

I am using Amazon s3 but here i am facing two problems

1.提交表单时,我无法直接将文件上传到Amazon服务器.我的意思是我必须将图像上传到我的PHP服务器上的upload folder,从那里我必须检索并将它们上传到s3 server .单击提交时,是否可以将图像直接上传到s3?

1.I can't directly upload files to amazon server when i submit form.I mean i have to upload images to an upload folder on my PHP server and from there i have to retrieve and upload them to s3 server. Is there a way to upload images directly to s3 when we click on submit?

2.如果我在s3 put object中通过了'public',那么我可以访问或查看文件,但是如果我将其公开,则每个人都可以查看文件.但是我需要保护所有文件,并且仅向经过身份验证的用户查看.有人可以建议我如何解决此问题吗?

2.If i pass 'public' in s3 put object then i can access or view files, but if i make it public every one can view files. But i need to protect all files and view only to the authenticated user. Can any one suggest me how to fix this issue?

try {           
    $s3 = \Storage::disk('s3');
    $s3->put($strFileName, file_get_contents($img_path.$strFileName), 'public');
} catch (Aws\Exception\S3Exception $e) {
    echo "There was an error uploading the file.\n"+$e;
}

在问问题之前,我已经阅读了stackoverflow的许多答案,但这并没有帮助我解决问题.谢谢.

Before asking questions i have read many answers from stackoverflow but it didnt helped me to fix my issue. Thanks.

推荐答案

我最近解决了这个问题.首先,是的,您可以直接上传到s3,这是我用于此的一些信息:

I recently tackled this problem. First off yes you can upload directly to s3 here is what I used for some info on this: http://docs.aws.amazon.com/AmazonS3/latest/dev/HTTPPOSTExamples.html

首先,您需要创建一个策略和签名服务器端,以添加到html表单中以上传文件.

First off you need to create a policy and signature server side to add to your html form for uploading files.

$policy = base64_encode(json_encode([
            "expiration" => "2100-01-01T00:00:00Z",
            "conditions" => [
                ["bucket"=> "bucketname"],
                ["starts-with", '$key', "foldername"],
                ["acl" => "public-read"],
                ["starts-with", '$Content-Type', "image/"],
                ["success_action_status" => '201'],
            ]
        ]));
$signature = base64_encode(hash_hmac('sha1',$policy,getenv('S3_SECRET_KEY'),true));

现在在表单的前端,我不使用提交"按钮,您可以使用提交"按钮,但是您需要捕获提交并阻止表单实际提交,直到上传完成.

Now on the frontend my form I don't use a submit button, you could use a submit button but you will need to catch the submit and prevent the form from actually submitting till after the upload finishes.

当我们单击保存"时,它会生成一个md5(使用npm进行安装)文件名,这样就无法真正猜测文件名,然后使用ajax将文件上传至S3.完成此操作后,它将文件数据和返回的aws数据放入隐藏的输入中,然后提交表单.它应该看起来像这样:

When we click save, it generates an md5 (use npm to install) filename so that file names can't really be guessed randomly, it then uses ajax to upload the file up to S3. After this is finished it puts the file data and returned aws data in a hidden input and submits the form. It should look something like this:

<form action="/post/url" method="POST" id="form">
    <input type="text" name="other_field" />
    <input type="file" class="form-control" id="image_uploader" name="file" accept="image/*" />
    <input type="hidden" id="hidden_medias" name="medias" value="[]" />
</form>
<input type="button" value="save" id="save" />
<script>
$(document).ready(function(){
    $('#save').click(function(){
            uploadImage(function () {
                $('#form').submit();
            });
    });
});
var uploadImage = function(callback) {
    var file = $('#image_uploader')[0].files[0];
    if(file !== undefined) {
        var data = new FormData();
        var filename = md5(file.name + Math.floor(Date.now() / 1000));
        var filenamePieces = file.name.split('.');
        var extension = filenamePieces[filenamePieces.length - 1];
        data.append('acl',"public-read");
        data.append('policy',"{!! $policy !!}");
        data.append('signature',"{!! $signature !!}");
        data.append('Content-type',"image/");
        data.append('success_action_status',"201");
        data.append('AWSAccessKeyId',"{!! getenv('S3_KEY_ID') !!}");
        data.append('key',filename + '.' + extension);
        data.append('file', file);

        var fileData = {
            type: file.type,
            name: file.name,
            size: file.size
        };

        $.ajax({
            url: 'https://{bucket_name}.s3.amazonaws.com/',
            type: 'POST',
            data: data,
            processData: false,
            contentType: false,

            success: function (awsData) {
                var xmlData = new XMLSerializer().serializeToString(awsData);
                var currentImages = JSON.parse($('#hidden_medias').val());
                currentImages.push({
                    awsData: xmlData,
                    fileData: fileData
                });
                $('#hidden_medias').val(JSON.stringify(currentImages));
                callback();
            },
            error: function (errorData) {
                console.log(errorData);
            }
        });
    }
};
</script>

监听提交的控制器然后从该输入字段解析JSON并创建Media实例(我创建的模型),并为每个图像存储awsDatafileData.

The controller listening for the submit then parses the JSON from that input field and creates an instance of Media (a model I created) and it stores the awsData and fileData for each image.

然后不要像这样将html图像标签指向s3文件:

Then instead of pointing html image tags to the s3 file like this:

<img src="https://{bucketname}.s3.amazonaws.com/filename.jpg" />

我做这样的事情:

<img src="/medias/{id}" />

然后,路由可以通过普通的auth中间件以及您在Laravel中需要做的所有事情.最后,该路由指向执行此操作的控制器:

Then the route can go through the normal auth middleware and all you need to do in Laravel. Finally, that route points to a controller that does this:

public function getResponse($id)
{
    $media = Media::find($id);
    return (new Response('',301,['Location' => $media->info['aws']['Location']]));
}

因此,此操作仅使用301重定向并将标头位置设置为实际的aws文件.由于我们在将文件上传到aws时会生成md5文件名,因此每个文件名都是md5,因此人们无法在存储桶中随机搜索aws文件.

So what this does is simply uses a 301 redirect and sets the header location to the actual aws file. Since we generate an md5 filename when we upload the file to aws each filename is an md5 so people couldn't randomly search for aws files in the bucket.

这篇关于Laravel保护Amazon S3存储桶文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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