Загрузка загрузочного файла Amazon AWS S3 Spring Boot - доступ запрещен

У меня есть автоматически сконфигурированное приложение AWS, Spring Boot, и я пытаюсь настроить конечную точку, которая будет просто загружать определенный файл из данного сегмента в Amazon S3. Я загрузил файл JPEG в корзину с моего компьютера с помощью консоли AWS - теперь я пытаюсь загрузить этот файл, используя мой Spring Boot API.

Я получаю следующую ошибку:com.amazonaws.services.s3.model.AmazonS3Exception: Access Denied (Service: Amazon S3; Status Code: 403; Error Code: AccessDenied;

Я создал пользователя и группу (пользователь в группе) на консоли AWS; пользователь / группа имеет полные права доступа на S3, а также доступ администратора. Я загрузил пару ключ доступа / секретный ключ и, для целей тестирования, буквально вставил ключи в файл application.properties, как показано ниже (ключи здесь не показаны, очевидно :)).

Я не понимаю, почему мне все еще отказывают в доступе. Я искал и работал над этим некоторое время; Я не могу найти решение этой проблемы, которая специфична для Spring Boot. Любая помощь будет принята с благодарностью.

application.properties:

cloud.aws.credentials.accessKey=myaccesskey
cloud.aws.credentials.secretKey=mysecretkey
cloud.aws.credentials.instanceProfile=false
cloud.aws.stack.auto=false

cloud.aws.region.auto=true
cloud.aws.region.static=myregion

SimpleResourceLoadingBean.java:

@RestController
public class SimpleResourceLoadingBean {

    private static Logger log = LoggerFactory.getLogger(HealthMonitorApplication.class);

    @Autowired
    private ResourceLoader resourceLoader;


    @RequestMapping("/getresource")
    public String resourceLoadingMethod() throws IOException {
        log.info("IN RESOURCE LOADER");

        Resource resource = this.resourceLoader.getResource("s3://s3.amazonaws.com/mybucket/myfile.ext");

        InputStream inputStream = resource.getInputStream();

        return inputStream.toString();
    }
}

pom.xml (только зависимости, которые имеют отношение к вопросу)

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-aws</artifactId>
            <version>1.1.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-aws-autoconfigure</artifactId>
            <version>1.1.0.RELEASE</version>
        </dependency>
 corecase26 июл. 2016 г., 02:15
Попытка и неудача: 1
 error2007s26 июл. 2016 г., 02:48
Вышеуказанное приложение Spring на локальном или на экземпляре EC2?
 error2007s26 июл. 2016 г., 02:57
Можете ли вы вставить то, что у вас есть в этом файле ~ / .aws / credentials без учетных данных на вашем локальном компьютере.
 corecase26 июл. 2016 г., 02:53
Приложение локальное.
 error2007s26 июл. 2016 г., 02:04
Измените cloud.aws.credentials.instanceProfile = false на true и проверьте, работает ли он?
 alltej09 февр. 2018 г., 18:04
Я думаю, что есть проблема, когдаResourceLoader инициализируется. Требуется клиент S3. Может быть связано с этой ошибкой:github.com/spring-cloud/spring-cloud-aws/issues/228
 corecase26 июл. 2016 г., 03:31
Хм, у меня на самом деле нет локального каталога с именем .aws. Тем не менее, у меня есть учетные данные (ключ доступа и секретный ключ), перечисленные в моем файле application.properties, и я знаю, что мое приложение правильно использует эти учетные данные, потому что я пытался использовать разные (случайные) учетные данные, и я получал соответствующие ошибки при выполнении поэтому (например, идентификатор ключа доступа не существует, секретный ключ не совпадает с идентификатором ключа доступа). Я не получаю никаких ошибок относительно моих учетных данных при использовании правильных учетных данных.

Ответы на вопрос(3)

Пожалуйста, исправьте шаблон URL

Resource resource = this.resourceLoader.getResource("s3://s3.amazonaws.com/mybucket/myfile.ext");

в

Resource resource = this.resourceLoader.getResource("s3://mybucket/myfile.ext");

Согласно документации образецs3://<bucket>/<object>Работает в весенней загрузке 2.0.6.RELEASE и в весеннем облаке Finchley.SR2 (проверено).

Ссылка :Spring Cloud AWS - загрузка файлов

Принятый ответ использует устаревшие API. Вот обновленная ревизия.

Сначала обновите зависимости maven:

 <dependency>
        <groupId>com.amazonaws</groupId>
        <artifactId>aws-java-sdk</artifactId>
        <version>1.11.274</version>
    </dependency>

AWSConfiguration.java

import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AWSConfiguration {

    @Value("${cloud.aws.credentials.accessKey}")
    private String accessKey;

    @Value("${cloud.aws.credentials.secretKey}")
    private String secretKey;

    @Value("${cloud.aws.region}")
    private String region;

    @Bean
    public BasicAWSCredentials basicAWSCredentials() {
        return new BasicAWSCredentials(accessKey, secretKey);
    }

    @Bean
    public AmazonS3 amazonS3Client(AWSCredentials awsCredentials) {
        AmazonS3ClientBuilder builder = AmazonS3ClientBuilder.standard();
        builder.withCredentials(new AWSStaticCredentialsProvider(awsCredentials));
        builder.setRegion(region);
        AmazonS3 amazonS3 = builder.build();
        return amazonS3;
    }
}

S3Service.java

import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.*;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Service
public class S3Service {

    @Autowired
    private AmazonS3 amazonS3;

    @Value("${cloud.aws.s3.bucket}")
    private String bucket;

    private PutObjectResult upload(String filePath, String uploadKey) throws FileNotFoundException {
        return upload(new FileInputStream(filePath), uploadKey);
    }

    private PutObjectResult upload(InputStream inputStream, String uploadKey) {
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, uploadKey, inputStream, new ObjectMetadata());

        putObjectRequest.setCannedAcl(CannedAccessControlList.PublicRead);

        PutObjectResult putObjectResult = amazonS3.putObject(putObjectRequest);

        IOUtils.closeQuietly(inputStream);

        return putObjectResult;
    }

    public List<PutObjectResult> upload(MultipartFile[] multipartFiles) {
        List<PutObjectResult> putObjectResults = new ArrayList<>();

        Arrays.stream(multipartFiles)
                .filter(multipartFile -> !StringUtils.isEmpty(multipartFile.getOriginalFilename()))
                .forEach(multipartFile -> {
                    try {
                        putObjectResults.add(upload(multipartFile.getInputStream(), multipartFile.getOriginalFilename()));
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                });

        return putObjectResults;
    }

    public ResponseEntity<byte[]> download(String key) throws IOException {
        GetObjectRequest getObjectRequest = new GetObjectRequest(bucket, key);

        S3Object s3Object = amazonS3.getObject(getObjectRequest);

        S3ObjectInputStream objectInputStream = s3Object.getObjectContent();

        byte[] bytes = IOUtils.toByteArray(objectInputStream);

        String fileName = URLEncoder.encode(key, "UTF-8").replaceAll("\\+", "%20");

        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        httpHeaders.setContentLength(bytes.length);
        httpHeaders.setContentDispositionFormData("attachment", fileName);

        return new ResponseEntity<>(bytes, httpHeaders, HttpStatus.OK);
    }

    public List<S3ObjectSummary> list() {
        ObjectListing objectListing = amazonS3.listObjects(new ListObjectsRequest().withBucketName(bucket));

        List<S3ObjectSummary> s3ObjectSummaries = objectListing.getObjectSummaries();

        return s3ObjectSummaries;
    }
}
 KIC25 сент. 2018 г., 13:44
Вы не должны хранить пароли в строковых полях ...
 Alex Kornhauser16 апр. 2018 г., 22:32
Когда я загружаю файл из этого, это бинарный файл, а не png, который я использовал.
 Wim Deblauwe02 мая 2018 г., 09:16
Не нужно ли закрыватьs3Object после прочтения входного потока (вdownload метод)?
Решение Вопроса

Разобрался с решением. Помимо конфигурации application.properties, мне пришлось создать класс конфигурации, который давал бы мне доступ к объекту AmazonS3Client при предоставлении соответствующих учетных данных. Я следовал этому примеру на GitHub:

https://github.com/brant-hwang/spring-cloud-aws-example/blob/master/src/main/java/com/axisj/spring/cloud/aws/AWSConfiguration.java

AWSConfiguration.java:

import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.regions.Region;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3Client;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AWSConfiguration {

    @Value("${cloud.aws.credentials.accessKey}")
    private String accessKey;

    @Value("${cloud.aws.credentials.secretKey}")
    private String secretKey;

    @Value("${cloud.aws.region}")
    private String region;

    @Bean
    public BasicAWSCredentials basicAWSCredentials() {
        return new BasicAWSCredentials(accessKey, secretKey);
    }

    @Bean
    public AmazonS3Client amazonS3Client(AWSCredentials awsCredentials) {
        AmazonS3Client amazonS3Client = new AmazonS3Client(awsCredentials);
        amazonS3Client.setRegion(Region.getRegion(Regions.fromName(region)));
        return amazonS3Client;
    }
}

После того, как это настроено, вы можете создавать объекты AmazonS3Client (с автосвязью) в других ваших классах и использовать клиент для отправки запросов в ваше облако S3. В этом примере в качестве службы используется класс-оболочка, чтобы упростить реализацию дополнительных классов контроллеров.

S3Wrapper.java:

import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.*;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Service
public class S3Wrapper {

    @Autowired
    private AmazonS3Client amazonS3Client;

    @Value("${cloud.aws.s3.bucket}")
    private String bucket;

    private PutObjectResult upload(String filePath, String uploadKey) throws FileNotFoundException {
        return upload(new FileInputStream(filePath), uploadKey);
    }

    private PutObjectResult upload(InputStream inputStream, String uploadKey) {
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, uploadKey, inputStream, new ObjectMetadata());

        putObjectRequest.setCannedAcl(CannedAccessControlList.PublicRead);

        PutObjectResult putObjectResult = amazonS3Client.putObject(putObjectRequest);

        IOUtils.closeQuietly(inputStream);

        return putObjectResult;
    }

    public List<PutObjectResult> upload(MultipartFile[] multipartFiles) {
        List<PutObjectResult> putObjectResults = new ArrayList<>();

        Arrays.stream(multipartFiles)
                .filter(multipartFile -> !StringUtils.isEmpty(multipartFile.getOriginalFilename()))
                .forEach(multipartFile -> {
                    try {
                        putObjectResults.add(upload(multipartFile.getInputStream(), multipartFile.getOriginalFilename()));
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                });

        return putObjectResults;
    }

    public ResponseEntity<byte[]> download(String key) throws IOException {
        GetObjectRequest getObjectRequest = new GetObjectRequest(bucket, key);

        S3Object s3Object = amazonS3Client.getObject(getObjectRequest);

        S3ObjectInputStream objectInputStream = s3Object.getObjectContent();

        byte[] bytes = IOUtils.toByteArray(objectInputStream);

        String fileName = URLEncoder.encode(key, "UTF-8").replaceAll("\\+", "%20");

        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        httpHeaders.setContentLength(bytes.length);
        httpHeaders.setContentDispositionFormData("attachment", fileName);

        return new ResponseEntity<>(bytes, httpHeaders, HttpStatus.OK);
    }

    public List<S3ObjectSummary> list() {
        ObjectListing objectListing = amazonS3Client.listObjects(new ListObjectsRequest().withBucketName(bucket));

        List<S3ObjectSummary> s3ObjectSummaries = objectListing.getObjectSummaries();

        return s3ObjectSummaries;
    }
}

Примечание. Для использования библиотеки ввода-вывода Apache Commons необходимо добавить следующую зависимость в pom.xml.

pom.xml:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-io</artifactId>
    <version>1.3.2</version>
</dependency>
 Rongeegee19 апр. 2019 г., 08:36
Я не знаю почему. Я сделал то, что вы сделали здесь. Но когда я компилирую и запускаю его. Это выдает ошибку «org.springframework.beans.factory.BeanCreationException: ошибка создания бина с именем org.springframework.cloud.aws.context.support.io.ResourceLoaderBeanPostProcessor # 0»: не удается разрешить ссылку на бин amazonS3 'при установке аргумента конструктора; вложенное исключение - org.springframework.beans.factory.BeanCreationException: ошибка создания бина с именем' amazonS3 ': невозможно разрешить ссылку на бин' org.springframework.cloud.aws.core.region.RegionProvid ... .. «;
 MV5306 дек. 2016 г., 08:18
Но spring-boot обеспечивает автоматическую настройку, добавляя аннотации EnableAutoConfiguration в один из ваших классов конфигурации. Так почему бы не настроить aws.
 Alex Kornhauser16 апр. 2018 г., 23:05
Я не могу открыть файл в моей системе .. Это точная проблема. Это странный двоичный файл, и я мало что могу с ним сделать.
 Alex Kornhauser16 апр. 2018 г., 22:33
Когда я загружаю файл из этого, это бинарный файл, а не png, который я использовал
 corecase17 апр. 2018 г., 00:58
Хм, это определенно странно ... Хотел бы я быть более полезным, но, к сожалению, я не слишком уверен, в чем проблема, потому что у меня никогда не было подобных проблем, насколько я себя помню - до тех пор, пока я мог чтобы загрузить файлы, они были точно такими же, как и в моем S3 ведро. Я бы предложил открыть новый вопрос о SO, в частности, о проблеме, с которой вы столкнулись, чтобы кто-то еще мог помочь вам.
 corecase16 апр. 2018 г., 22:39
Это было довольно давно, но вам, вероятно, придется читать файл как png, используя программу чтения изображений или что-то в этом роде, если вы пытаетесь прочитать его в своем коде Java. Если вы просто пытаетесь открыть файл в своей файловой системе, у меня не было проблем с этим; он буквально загружает файл напрямую в вашу файловую систему (в любую директорию, которую вы указали).

Ваш ответ на вопрос