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

Laravel保护Amazon s3桶文件

闾丘谦
2023-03-14

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

1.当我提交表单时,我不能直接将文件上传到亚马逊服务器。我的意思是我必须将图像上传到我的PHP服务器上的上传文件夹,然后从那里检索并将它们上传到s3服务器。当我们单击提交时,有没有办法直接将图像上传到s3

2.如果我在s3放置对象中传递'public',那么我可以访问或查看文件,但如果我将其公开,每个人都可以查看文件。但我需要保护所有文件并仅向经过身份验证的用户查看。有人能建议我如何解决这个问题吗?

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的答案,但它并没有帮助我解决我的问题。谢谢。

共有3个答案

林昱
2023-03-14

我最近解决了这个问题。首先,是的,你可以直接上传到s3这里是我用来提供一些信息的:http://docs.aws.amazon.com/AmazonS3/latest/dev/HTTPPOSTExamples.html

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

$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));

现在在前端,我的表单不使用提交按钮,您可以使用提交按钮,但您需要捕获提交并防止表单在上传完成之前实际提交。

当我们单击保存时,它会生成一个md5(使用npm安装)文件名,这样文件名就不能真正随机猜测,然后它使用ajax将文件上传到S3。完成后,它将文件数据返回的aws数据放在隐藏输入中并提交表单。它应该看起来像这样:

<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

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

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

我做这样的事情:

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

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

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

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

颜杰
2023-03-14

1.当我们点击提交时,有没有办法直接上传图像

对呀

怎样:

您需要分两部分使用JavaScript(使用AJAX)来执行此操作;

a) 当用户单击“提交”时,您将捕获此事件,首先上载文件(请参阅http://docs.aws.amazon.com/AWSJavaScriptSDK/guide/browser-examples.html然后通过AJAX提交表单并处理响应。

然而:

这允许用户上载任何内容,并可能导致问题。有一些技巧(就在下面的示例中)可以创建15分钟的经过身份验证的URL(变量),但是如果用户花费的时间超过15分钟,或者试图在15分钟内上载100个文件,或者上载图像文件以外的其他文件,或者格式不正确的图像文件等,会发生什么情况。

更安全的做法是,将图像拉入服务器,验证它们是否为所需类型/大小的图像,然后从服务器上载。

当然,如果这是一个简单的管理工具,并且您可以控制谁访问代码,那么就使用它-希望您只上传您期望的内容。

2、我需要保护所有文件并仅向经过身份验证的用户查看

“经过身份验证的用户”:如果您的意思是“上传图像的用户”,那么仅s3不提供该功能,但CloudFront提供。您可以发布预先授权的URL或签名的cookie:http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-choosing-signed-urls-cookies.html

如果“经过身份验证的用户”是指上传文件的人,那么根据文档,在Laravel类中,如果不访问底层客户端,这是不可能的<默认情况下,代码>公用和<代码>专用是您唯一的可见性选项,它们被转换为公共读取,但您需要经过身份验证的读取、<代码>桶所有者读取或其他固定授权(参考:http://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl)如果通过身份验证的读取或其他固定acl授予没有提供您所需的权限配置文件,您可以创建自己的权限配置文件(详细信息在同一页上)。

解决方案是获取底层客户端,然后直接执行put对象。(然后如果你走得那么远,你不妨放弃Laravel库,引入s3并自己完成——然后你就可以完全控制一切)。

$client = $disk->getDriver()->getAdapter()->getClient();

$client->putObject([
    'Bucket' => $bucket,
    'Key'    => $fileName,
    'Body'   => $fileBody,
    'ACL'    => 'authenticated-read'  /* Or which ACL suits */
]);
於功
2023-03-14

对于您的第一个问题,它可以直接将图像上传到AWS S3。

$s3 = \Storage::disk('s3')->getDriver();
$s3->put($filePath, file_get_contents($file), array('ContentDisposition' => 'attachment; filename=' . $file_name . '', 'ACL' => 'public-read'));

您应该指定您的文件路径和从表单中获取的文件。

 类似资料:
  • 我一直尝试访问上载图像URL,但图像链接在一段时间后过期,并显示错误“AccessDenied” 我还公开了水桶政策 {“版本”:“2008-10-17”,“语句”:[{“SID”:“AllowPublicRead”,“Effect”:“Allow”,“Principal”:{“AWS”:“”},“Action”:“S3:GetObject”,“Resource”:“arn:AWS:S3:::Pr

  • 我是拉威尔5号的新手,我只是想知道如何保护特定路线?我正在使用默认的身份验证中间件来保护我的路由,这只有在您登录时才可访问。所以我有这个。 如何仅保护/auth/register?不影响其他人的登录吗? 默认情况下,在我的路由组之外,我有此选项。 我只希望登录的用户访问默认的注册页面。我的登录用户都是管理员。

  • 我有一个只能使用签名url访问的S3存储桶。到目前为止,我使用GeneratePresignedUrlRequest(Java)生成签名url。现在我想通过CloudFront访问我的存储桶。问题是我如何在这种情况下生成签名url?

  • 目前,我正在尝试将一个文件上载到AmazonS3存储桶,我对此进行了一些研究,发现如果文件足够大,类TransferManager会将文件拆分为小块,然后使用多个线程并行上载。现在在应用程序中,我们正在创建一个AmazonS3客户端实例(在应用程序开始时创建的一个bean),并使用该AmazonS3客户端为用户上传文件所需的每个文件创建TransferManager类实例,文件上传完成后(由Tra

  • 我正在使用MIP文件示例命令行界面来应用标签。当尝试应用设置了保护的标签时,我得到“标签需要临时保护,但保护尚未设置”错误。因此,我尝试使用“- protect”选项保护该文件,并得到以下错误消息:“发生了不好的事情:服务不接受auth令牌。挑战:[' Bearer resource = " https://aadrm . com ",realm= " ",authorization = " ht

  • 我想用vba来保护我的word文档。 的确,这是可能的,但我已经通过以下链接搜索了如何取消文档保护: http://www.aurelp.com/2015/04/01/how-to-unlock-a-microsoft-word-document-step-by-stepsolved/ 有没有其他方法可以成功地保护文档不被未经授权的用户使用?