gib65
gib65

Reputation: 2017

Why do I not have access to my firebase storage images?

I have two image files uploaded to firebase storage:

enter image description here

capsule house.jpg was uploaded through the UI (clicking the Upload file button).

upload_64e8fd... was uploading from my backend server (node.js) using this:

const bucket = fbAdmin.storage().bucket('gs://assertivesolutions2.appspot.com');
const result = await bucket.upload(files.image.path);

capsule house.jps is recognized as a jpeg and a link to it is supplied in the right hand margin. If I click on it, I see my image in a new tab. You can see for yourself:

https://firebasestorage.googleapis.com/v0/b/assertivesolutions2.appspot.com/o/capsule%20house.jpg?alt=media&token=f5e0ccc4-7916-4245-b813-dbdf1838556f

upload_64e8fd... is not recognized as any kind of image file and no link it provided.

The result returned on the backend is a huge json object with the following fields:

"selfLink": "https://www.googleapis.com/storage/v1/b/assertivesolutions2.appspot.com/o/upload_64e8fd09f787acfe2728ae73158e20ab"
"mediaLink": "https://storage.googleapis.com/download/storage/v1/b/assertivesolutions2.appspot.com/o/upload_64e8fd09f787acfe2728ae73158e20ab?generation=1590547279565389&alt=media"

The first one sends me to a page that says this:

{
  "error": {
    "code": 401,
    "message": "Anonymous caller does not have storage.objects.get access to the Google Cloud Storage object.",
    "errors": [
      {
        "message": "Anonymous caller does not have storage.objects.get access to the Google Cloud Storage object.",
        "domain": "global",
        "reason": "required",
        "locationType": "header",
        "location": "Authorization"
      }
    ]
  }
}

The second one gives me something similar:

Anonymous caller does not have storage.objects.get access to the Google Cloud Storage object.

The rules for my storage bucket are as follows:

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if true;
    }
  }
}

I'm allowing all reads and writes.

So why does it say I don't have access to see my image when it's uploaded through my backend server?

I'd also like to know why it doesn't recognize it as a jpeg when it's uploaded through my backend server, but it does when uploaded through the UI, but I'd like to focus on the access issue for this question.

Thanks.

Upvotes: 1

Views: 1345

Answers (3)

Francis Umeanozie
Francis Umeanozie

Reputation: 41

You need to allow public read access

public String uploadImage(String name, String image) {
    final byte[] bytes = Util.convertBase64ToByteArray(image);
    final String imageExtension = Util.getImageExtensionFromBase64(image);
    final String img = name+"."+imageExtension;

    Storage storage = StorageOptions.getDefaultInstance().getService();

    final BlobId blobId = BlobId.of(BUCKET_NAME, img);
    final BlobInfo blobInfo = BlobInfo.newBuilder(blobId)
            .setContentType("image/"+imageExtension)
            .setAcl(new ArrayList<>(List.of(Acl.of(Acl.User.ofAllUsers(), Acl.Role.READER)))) // allow read access
            .build();
      
    final Blob blob = storage.create(blobInfo, bytes);
    return blob.getMediaLink();
}

Upvotes: 0

Carl Walsh
Carl Walsh

Reputation: 6959

The other answer helped me! I have no idea why the Console had me make those security rules if they won't apply...

Based on nodejs docs (and probably other languages) there is a simple way to make the file public during upload:

const result = await bucket.upload(files.image.path, {public: true});

This same option works for bucket.file().save() and similar APIs.

Upvotes: 1

gso_gabriel
gso_gabriel

Reputation: 4670

By default, the files are uploaded as private, unless you change your bucket settings, as mentioned here. The below code is an example of how to change the visibility of your documents.

/**
 * {@inheritdoc}
 */
public function setVisibility($path, $visibility)
{
    $object = $this->getObject($path);

    if ($visibility === AdapterInterface::VISIBILITY_PRIVATE) {
        $object->acl()->delete('allUsers');
    } elseif ($visibility === AdapterInterface::VISIBILITY_PUBLIC) {
        $object->acl()->add('allUsers', Acl::ROLE_READER);
    }

    $normalised = $this->normaliseObject($object);
    $normalised['visibility'] = $visibility;

    return $normalised;
}

You can check how to set that via console, following the tutorial in the official documentation: Making data public

Besides that, as indicated in the comment by @FrankvanPuffelen, you won't have a generated URL for the file to be accessed. You can find more information about it here.

Let me know if the information helped you!

Upvotes: 1

Related Questions