Laravel защищает файлы Amazon s3 bucket

Я использую Amazon s3, но здесь я столкнулся с двумя проблемами

1. Я не могу напрямую загружать файлы на сервер амазонки, когда я отправляю форму. Я имею в виду, что мне нужно загружать изображения для загрузки папки, а оттуда мне нужно загрузить и загрузить на s3 server Есть ли способ загружать изображения напрямую, когда мы нажимаем на Отправить ?

2.if я передаю 'public' в s3 put object тогда только я могу получить доступ или просматривать файлы, но если я сделаю его общедоступным, каждый может просматривать файлы, но мне нужно защитить все файлы и просмотреть только для аутентифицированного пользователя. мне как решить эту проблему?

 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, но это не помогло мне исправить мою проблему. Спасибо.

Я недавно занялся этой проблемой. Сначала да, вы можете загрузить прямо на 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 (модель, которую я создал), и он хранит awsData и fileData для каждого изображения.

Затем вместо указания html-тегов изображений в файл s3, например:

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

Я делаю что-то вроде этого:

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

Затем маршрут может пройти через обычное промежуточное ПО и все, что вам нужно сделать в Laravel. Наконец, этот маршрут указывает на контроллер, который делает это:

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

Так что это просто использует 301 переадресацию и устанавливает местоположение заголовка в фактический файл aws. Поскольку мы генерируем имя файла md5, когда мы загружаем файл в aws, каждое имя файла является md5, чтобы люди не могли случайно искать aws-файлы в ведре.

Для первого вопроса можно напрямую загрузить изображения в AWS S3.

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

Вы должны указать путь к файлу и файл, который вы получаете из формы.

1. есть ли способ загружать изображения напрямую, когда мы нажимаем кнопку «Отправить»

да

Как:

Вам нужно сделать это, используя JavaScript (с AJAX) в двух частях;

а) когда пользователь нажимает «отправить», вы задерживаете это событие, сначала загрузите файл (см. http://docs.aws.amazon.com/AWSJavaScriptSDK/guide/browser-examples.html для примера), и b) затем отправьте формы через AJAX и обрабатывать ответ.

Однако:

Это позволяет пользователю загружать что угодно и может вызвать проблемы. Есть советы (чуть ниже примера) для создания аутентифицированных URL-адресов в течение 15 минут (переменная), но что происходит, если пользователь занимает более 15 минут или пытается загрузить 100 файлов за 15 минут или загружает что-то, отличное от файла изображений, или плохо отформатированный файл изображения и т. д.

Гораздо безопаснее подключиться к вашему серверу и убедиться, что это изображения и тип / размер, который вам нужен, а затем загрузить с сервера.

Конечно, если это простой инструмент администрирования, и вы контролируете, кто обращается к коду, то идите на него – надеюсь, вы будете загружать только то, что ожидаете.

2. Мне нужно защитить все файлы и просмотреть только аутентифицированного пользователя

Под «аутентифицированным пользователем»: если вы имеете в виду «пользователь, загрузивший изображение», тогда только s3 не предоставляет функциональные возможности, но CloudFront делает это. Вы можете опубликовать предварительно авторизированные URL-адреса или подписанные файлы cookie: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-choosing-signed-urls-cookies.html

Если «аутентифицированный пользователь» означает человека, который загрузил файл, то, согласно документам, это невозможно в классе Laravel без доступа к базовому клиенту. public и private – это ваши единственные параметры видимости по умолчанию, которые переведены на public-read , но вам необходимо пройти authenticated-read bucket-owner-read или одну из других консервированных грантов (ref: http: //docs.aws.amazon .com / AmazonS3 / latest / dev / acl-overview.html # canned-acl ) Если authenticated-read или другие консервированные ACL-гранты не предоставляют профиль разрешений, который вам нужен, вы можете создать свой собственный (подробнее об этом на той же странице).

Решение состоит в том, чтобы захватить базового клиента, а затем непосредственно поставить объект. (И тогда, если вы заходите так далеко, вы можете также сорвать библиотеку Laravel и потянуть s3 и сделать все сами – тогда у вас есть полный контроль над всем).

 $client = $disk->getDriver()->getAdapter()->getClient(); $client->putObject([ 'Bucket' => $bucket, 'Key' => $fileName, 'Body' => $fileBody, 'ACL' => 'authenticated-read' /* Or which ACL suits */ ]); 

Решение вашего вопроса, который я использую, но без laravel.

1. Для загрузки любого файла непосредственно в Buzz Amazon AWS S3 в определенную папку вы можете сделать это следующим образом.

HTML

 <form action="upload.php" enctype="multipart/form-data"> <input type="file" name="file" id="file" /> <button type="submit">Upload file</button> </form> 

PHP – upload.php

Включить aws php sdk

 require "vendor/autoload.php"; 

Инициализировать клиент S3

 $credentials = new Aws\Credentials\Credentials( '<AWS ACCESS KEY>', '<AWS ACCESS SECRET>' ); $s3Client = Aws\S3\S3Client::factory( [ 'credentials' => credentials 'region' => 'us-east-1', 'version' => 'latest' ] ); 

Создать объект для загрузки файлов

 $uploadEntity = array( 'Bucket' => <S3 Bucket Name>, 'Key' => '<Upload_Folder_If_Any>/<FileName>', 'Body' => fopen($_FILES['file']['tmp_name'], 'r+'), //'ContentDisposition' => 'attachment; filename="<FileName>"' <-- If need to allow downloading ); 

Загрузить в s3 Bucket

 try { // $result will be Aws\Result object $result = $s3Client->putObject($uploadEntity); } catch (Aws\S3\Exception\S3Exception $exception) { // S3 Exception } 

2. Теперь для загрузки загруженных файлов только для прошедших проверку подлинности пользователей

Во-первых, вам нужно будет создать политику private bucket для s3 Bucket.

Политика Bucket – для создания политики ведра вы можете использовать Generator Policy . Используя это, вы можете создать такую ​​политику. Скопировано с сайта Improve.dk

 { "Id": "Policy1319566876317", "Statement": [ { "Sid": "Stmt1319566860498", "Action": [ "s3:GetObject" ], "Effect": "Allow", "Resource": "arn:aws:s3:::<BucketName>/*", "Principal": { "CanonicalUser": [ "<CannoicalUserId_of_OAI>" ] } } ] } 

Во-вторых, вам нужно будет настроить частное веб-распределение облачной системы s3 Bucket. Только делая это, вы сможете обслуживать свое содержимое для аутентифицированных пользователей только через подписанный urs или подписанный файл cookie

В-третьих, для создания подписанного URL- кода вам понадобится файл pem, который вы получите только от консоли aws.

Создать подписанный URL

 $cdnName = '<AWS CLOUDFRONT WEB DISTRIBUTION CDN>'; $assetName = '<UPLOAD_FOLDER_IF_ANY>/<FILENAME>'; $expiry = time() + 300; // 5 mins expiry time, ie. the signed url will be valid only for 5 mins $cloudfront = CloudFrontClient::factory(array( 'credentials' => $credentials, 'region' => 'us-east-1', 'version' => 'latest' )); // Use this for creating signed url $signedUrl = $cloudFront->getSignedUrl([ 'url' => $cdnName . '/' . $assetName, 'expires' => $expiry, 'private_key' => '/path/to/your/cloudfront-private-key.pem', 'key_pair_id' => '<cloudfront key pair id>' ]); // Use this for signed cookie $signedCookie = $cloudFront->getSignedCookie([ 'url' => $cdnName . '/' . $assetName, 'expires' => $expiry, 'private_key' => '/path/to/your/cloudfront-private-key.pem', 'key_pair_id' => '<cloudfront key pair id>' ]);