2016-07-25 11 views
6

Mam automatycznie skonfigurowaną aplikację AWS, Spring Boot i próbuję skonfigurować punkt końcowy, który po prostu pobierze konkretny plik z danego zasobnika w Amazon S3. Przesłałem plik JPEG do pojemnika z mojego komputera za pomocą konsoli AWS - teraz próbuję pobrać ten plik za pomocą mojego interfejsu Spring Boot API.Spring Boot Amazon AWS S3 Bucket File Download - Access Denied

Dostaję następujący błąd: com.amazonaws.services.s3.model.AmazonS3Exception: Access Denied (Service: Amazon S3; Status Code: 403; Error Code: AccessDenied;

Stworzyłem użytkownika i grupę (użytkownik jest w grupie) na konsoli AWS; użytkownik/grupa ma pełne uprawnienia dostępu na S3, a także dostęp administratora. Pobrałem parę klucza dostępu/klucza tajnego i, w celach testowych, dosłownie wkleiłem klucze do mojego pliku application.properties, jak pokazano poniżej (klucze nie są tutaj pokazane, oczywiście :)).

Jestem zdezorientowany, dlaczego nadal otrzymuję odmowę dostępu. Szukałem i pracowałem nad tym przez jakiś czas; Nie mogę znaleźć rozwiązania tego problemu, który jest charakterystyczny dla Spring Boot. Każda pomoc będzie bardzo ceniona.

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 (Tylko Zależności, które są istotne z punktu widzenia kwestii)

 <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> 
+0

Zmień wartość pola cloud.aws.credentials.instanceProfile = false na true i sprawdź, czy działa? – error2007s

+0

Próbowałem i zawiodłem: 1 – corecase

+0

Czy powyższa aplikacja Spring działa lokalnie lub na instancji EC2? – error2007s

Odpowiedz

13

zorientowali się rozwiązanie. Poza konfiguracją application.properties, musiałem stworzyć klasę konfiguracji, która dałaby mi dostęp do obiektu AmazonS3Client po podaniu odpowiednich poświadczeń. Śledziłem ten przykład na 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; 
    } 
} 

Po to jest skonfigurowany, można tworzyć obiekty AmazonS3Client (autowired) w swoich innych klas i używać klienta do wysyłaj żądania do chmury S3. W przykładzie użyto klasy opakowania jako usługi w celu ułatwienia implementacji dodatkowych klas kontrolerów.

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; 
    } 
} 

Uwaga: Poniższy zależność musi być dodany do pom.xml w celu korzystania z biblioteki Apache Commons IO.

pom.xml:

<dependency> 
    <groupId>org.apache.commons</groupId> 
    <artifactId>commons-io</artifactId> 
    <version>1.3.2</version> 
</dependency> 
+0

Ale wiosna-boot zapewnia automatyczną konfigurację przez dodanie adnotacji EnableAutoConfiguration do jednej z twoich klas konfiguracji., Więc dlaczego nie konfiguruję aws. – M05

2

Zaakceptowanych odpowiedź używa nieaktualnych interfejsów API. Oto zaktualizowana wersja.

początku zaktualizujemy zależnościami 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; 
    } 
} 
Powiązane problemy