Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

My objective is to create an application that should allow to stream audio from S3 buckets. My backend is actually returning a list of titles to stream. In my controller I have a basic call:

@GetMapping(
        produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Flux<AudioResponseDto>> getPlaylist() {
    return new ResponseEntity<>(this.audioService.getPlaylist(), HttpStatus.OK);

In my service:

@Override
public Flux<AudioResponseDto> getPlaylist() {
    return audioRepository.findAll().map(AudioUtils::audioEntityToAudioResponseDto);

As a matter of fact my code is working and i'm returning AudioResponseDto but it's rather dirty: anyone can download the file because the URL link is visible Here is my model response object:

public class AudioResponseDto {
    private String id;
    private String title;
    private String artist;
    private String album;
    private int year;
    private byte[] albumImage;
    private int length;
    private String streamUrl;

My streamUrl is a link to a file from S3 bucket and looks like this:

https://custom-storage-audio.s3.eu-west-3.amazonaws.com/{folderId]/my+file.mp3

My front app is running on angular. My work is highly inspired from Shibaji Debnath tutorial that allowed me to have a first approach on audio streaming. I call my springboot app and retrieve a playlist. I implemented a service to call my API:

getFiles(): Observable<AudioStream[]> {
  return this.http.get<AudioStream[]>("http://localhost:8080/audio/tracks")

My AudioStream model is based on the AudioResponseDto object:

export interface AudioStream {
  id: string;
  title: string;
  artist: string;
  album: string;
  year: number;
  albumImage: any[];
  length: number;
  streamUrl: string;

To play a title, a method is called:

openFile(file: AudioStream, index: number) {
  this.currentFile = { index, file };
  this.audioService.stop();
  this.playStream(file.streamUrl);
playStream(url: string) {
  this.audioService.playStream(url).subscribe( (events: any) => {
    if(events.type == 'ended'){
      if(!this.isLastPlaying()){
        this.next();
      }else{
        this.openFile(this.files[0], 0);

From my service:

playStream(url: string) {
  return this.streamObservable(url).pipe(takeUntil(this.stop$));

I do have security concerns:

  • I would like to make the file readable but not available for download for guests
  • Make the title available for download in specific conditions
  • I would like to have an url each time a title is listened
  • Ideally, my AudioResponse should not contain web url that make the track available for download, I would like to stream from S3 without sharing URL by passing bytes array, without downloading possibility, and without giving the link to the bucket.

    I do think I should create a route that retrieve the file from S3 in springboot and return a content to stream. I will also have the same issue concerning videos :)

    I hope that I make myself clear enough. Thanks

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.