Home > other >  Unique node connected to user - Firebase Realtime Database
Unique node connected to user - Firebase Realtime Database

Time:09-04

I have a functioning app where users can signup/login, upload images and view images that have already been uploaded. However when an image is shared it shows up for every user and I want the images to be user-specific (you can only see the images that you uploaded). I can't quite get the rules right on storage and realtime database. Here are my rules for realtime database:

{
  "rules": {
    "users": {
      "$uid": {
        ".write": "$uid === auth.uid",
        ".read": "$uid === auth.uid"
      }
    }
  }
}

and the rules for firebase storage:

rules_version = '1';
service firebase.storage {
    match /users/{userid} {
    allow read: if request.auth.uid == userId;
    allow write: if request.auth.uid == userId; 
    }
}

Here is the code for uploading image.

    private void uploadToFirebase(Uri uri){

        //StorageReference fileRef = reference.child(System.currentTimeMillis()   "."   getFileExtension(uri));
        if (FirebaseAuth.getInstance().getCurrentUser() != null) {
            String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
            StorageReference fileRef = reference
                    .child(uid)
                    .child(System.currentTimeMillis()   "."   getFileExtension(uri));

            fileRef.putFile(uri).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
                @Override
                public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {

                    fileRef.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
                        @Override
                        public void onSuccess(Uri uri) {

                            Model model = new Model(uri.toString());
                            String modelId = root.push().getKey();
                            root.child(modelId).setValue(model);
                            progressBar.setVisibility(View.INVISIBLE);
                            Toast.makeText(MainActivity.this, "Uploaded Successfully", Toast.LENGTH_SHORT).show();
                            imageView.setImageResource(R.drawable.ic_baseline_add_photo_alternate_24);
                        }
                    });
                }
            }).addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
                @Override
                public void onProgress(@NonNull UploadTask.TaskSnapshot snapshot) {

                    progressBar.setVisibility(View.VISIBLE);
                }
            }).addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {
                    progressBar.setVisibility(View.INVISIBLE);
                    Toast.makeText(MainActivity.this, "Uploading Failed !!", Toast.LENGTH_SHORT).show();
                }
            });
        }
    }

Here is my code for the show images activity.

package com.example.auth;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.os.Bundle;

import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;

import java.util.ArrayList;

public class ShowActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    private ArrayList<Model> list;

    private MyAdapter adapter;

    private DatabaseReference root = FirebaseDatabase.getInstance().getReference("Image");

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_show);

        recyclerView = findViewById(R.id.recyclerview);
        recyclerView.setHasFixedSize(true);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        list = new ArrayList<>();
        adapter = new MyAdapter(this , list);
        recyclerView.setAdapter(adapter);


        root.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                for (DataSnapshot dataSnapshot : snapshot.getChildren()){
                    Model model = dataSnapshot.getValue(Model.class);
                    list.add(model);
                }
                adapter.notifyDataSetChanged();
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {

            }
        });
    }
}

Using these rules, when I try to upload an image I get the logcat error "StorageException has occurred. User does not have permission to access this object." Any insight as to why this is happening and how to correct my rules would be appreciated. Thanks!

CodePudding user response:

You initialize reference like this:

private StorageReference reference = FirebaseStorage.getInstance().getReference();

Then you try to upload a file with:

StorageReference fileRef = reference.child(System.currentTimeMillis()   "."   getFileExtension(uri));
fileRef.putFile(uri)....

To the path you try to upload to is /$time $extension, which does not include any user identification. Since your security rules only allow the user to put files under their own UID, they reject the upload.

To upload under the current user's UID:

if (FirebaseAuth.getInstance().getCurrentUser() != null) {
  String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
  StorageReference fileRef = reference
    .child(uid)
    .child(System.currentTimeMillis()   "."   getFileExtension(uri));
  ...
}
  • Related