简体   繁体   中英

Android firebase database permission denied despite the fact that a user is logged in

I've never used firebase database and I think I'm having some "newbie" problems and I just can't solve it. Getting to the point:

My database is structured like this:

database
 /cookbooks
    /key: cookbook id, value: CookBook.class
       /recipes

 /recipes
    /key: recipe id, value: Recipe.class
 / users
   /cookbooks
      /cookbook id

What I want to achieve is that on start of the app data is downloaded from those repositories (from all of them) and stored in a DataManager class.

Below are the rules in my database:

{
  "rules": {
    "recipes-309da": {
      "cookbooks": {
        ".read": "auth != null",
            ".write": "auth != null",
    },

    "recipes": {
        ".read": "auth != null",
            ".write": "auth != null",
    },

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

The problem is that I'm keep getting "Permission denied" notification. Data is not being downloaded nor I can save any data to the database.

I would be grateful for any help you could give me!

Some relevant code:

public static final String STORAGE_PATH_PHOTOS_UPLOADS = "photos_uploads/";
    public static final String DATABASE_PATH_PHOTOS_UPLOADS = "photos_uploads";
    public static final String DATABASE_PATH_RECIPES_UPLOADS = "recipes";
    public static final String DATABASE_PATH_COOKBOOKS_UPLOADS = "cookbooks";
    public static final String DATABASE_PATH_USERS = "users";

private StorageReference mStorageReference = FirebaseStorage.getInstance().getReference();
    private DatabaseReference mDatabasePhotosUploads = FirebaseDatabase.getInstance().getReference(ConstantsForUploads.DATABASE_PATH_PHOTOS_UPLOADS);
    private DatabaseReference mDatabaseRecipesUploads = FirebaseDatabase.getInstance().getReference(ConstantsForUploads.DATABASE_PATH_RECIPES_UPLOADS);
    private DatabaseReference mDatabaseCookBooksUploads = FirebaseDatabase.getInstance().getReference(ConstantsForUploads.DATABASE_PATH_COOKBOOKS_UPLOADS);
    private DatabaseReference mDatabaseUsersUploads = FirebaseDatabase.getInstance().getReference(ConstantsForUploads.DATABASE_PATH_USERS);

    private DatabaseReference mDatabaseRecipesUploadsBelowUser = mDatabaseRecipesUploads.child(FirebaseAuth.getInstance().getCurrentUser().getUid());
    private DatabaseReference mDatabaseCookBooksKeyUploadsInUserBooks = mDatabaseUsersUploads.child(FirebaseAuth.getInstance().getCurrentUser().getUid()).child("books");

At start of MainActivity I use a method attachListeners(ALL) from GeneralDataManager.

public void attachListeners(int staticIntFromGeneralUploader) {
    // attaches and detaches SingleValueEventListeners so it can download data while opening an app
    mDatabaseRecipesUploadsBelowUser.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            mCurrentUserRecipesList = new ArrayList<>();
            mCurrentUserRecipeTitleKeyMap = new HashMap<>();

            for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
                Recipe recipe1 = snapshot.getValue(Recipe.class);
                mCurrentUserRecipesList.add(recipe1);
                mCurrentUserRecipeTitleKeyMap.put(recipe1.getTitle(), snapshot.getKey());
            }
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });

    mDatabaseCookBooksUploads.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            mRecipesInCookBooksMap = new HashMap<>();

            for (DataSnapshot snapshotOfCookBooks : dataSnapshot.getChildren()) {
                String cookBookKey1 = snapshotOfCookBooks.getKey();

                if (mCurrentUserCookBookKeyTitleMap.containsKey(cookBookKey1)) {
                    CookBook cookbook1 = snapshotOfCookBooks.getValue(CookBook.class);
                    for (DataSnapshot snapshotOfRecipesInsideCookBooks : snapshotOfCookBooks.getChildren()) {
                        if (snapshotOfRecipesInsideCookBooks.getValue() == Recipe.class) {
                            Recipe recipe1 = snapshotOfRecipesInsideCookBooks.getValue(Recipe.class);
                            if (!mRecipesInCookBooksMap.containsKey(cookbook1)) {
                                mRecipesInCookBooksMap.put(cookbook1, new ArrayList<Recipe>());
                                mRecipesInCookBooksMap.get(cookbook1).add(recipe1);
                            } else {
                                mRecipesInCookBooksMap.get(cookbook1).add(recipe1);
                            }
                        }

                    }
                }
            }

            for (CookBook logCookBook : mRecipesInCookBooksMap.keySet()) {
                for (Recipe logRecipe : mRecipesInCookBooksMap.get(logCookBook)) {
                    Log.e("R inside C", "CookBook " + logCookBook.getTitle() + " containts Recipe: " + logRecipe.getTitle());
                }
            }

            // attaches listener so that fragment displaying cookbooks receives arraylist containing cookbooks
            if (mRecipesInCookBooksMap != null && mRecipesUpdateListener != null) {
                mRecipesUpdateListener.onMapChanged((HashMap<CookBook, ArrayList<Recipe>>) mRecipesInCookBooksMap);
            }
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });

    mDatabaseCookBooksKeyUploadsInUserBooks.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            mCurrentUserCookBookKeyTitleMap = new HashMap<>();

            for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
                String key1 = snapshot.getKey();
                String title1 = snapshot.getValue(String.class);

                mCurrentUserCookBookKeyTitleMap.put(key1, title1);
            }
            Log.e("CurrentUserCookBook", "Updated" + mCurrentUserCookBookKeyTitleMap.keySet());
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });

    if (staticIntFromGeneralUploader == GeneralDataManager.RECIPE_UPDATES_LISTENER) {
        mDatabaseRecipesUploadsBelowUser.addValueEventListener(recipeUpdatesListener);

    } else if (staticIntFromGeneralUploader == GeneralDataManager.COOKBOOK_UPDATES_LISTENER) {
        mDatabaseCookBooksKeyUploadsInUserBooks.addValueEventListener(cookBookKeysInUserBooksUpdatesListener);

    } else if (staticIntFromGeneralUploader == GeneralDataManager.RECIPE_IN_COOKBOOK_UPDATES_LISTENER) {
        mDatabaseCookBooksUploads.addValueEventListener(cookBookDatabaseListener);

    } else if (staticIntFromGeneralUploader == GeneralDataManager.ATTACH_ALL_LISTENERS) {
        mDatabaseRecipesUploadsBelowUser.addValueEventListener(recipeUpdatesListener);
        mDatabaseCookBooksKeyUploadsInUserBooks.addValueEventListener(cookBookKeysInUserBooksUpdatesListener);
        mDatabaseCookBooksUploads.addValueEventListener(cookBookDatabaseListener);
    }

}

Part of MainActivity:

@Override
protected void onStart() {
    super.onStart();

    // new ImageLoadTask(imageUrl, mProfilePicture).execute();
    //Referring to the name of the User who has logged in currently and adding a valueChangeListener
    myFirebaseRef.child(mUid).child("name").addValueEventListener(new ValueEventListener() {
        //onDataChange is called every time the name of the User changes in your Firebase Database
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            //Inside onDataChange we can get the data as an Object from the dataSnapshot
            //getValue returns an Object. We can specify the type by passing the type expected as a parameter
            String data = dataSnapshot.getValue(String.class);

            GeneralDataManager.getInstance().attachListeners(GeneralDataManager.ATTACH_ALL_LISTENERS);
        }

        //onCancelled is called in case of any error
        @Override
        public void onCancelled(FirebaseError firebaseError) {
            Toast.makeText(getApplicationContext(), "" + firebaseError.getMessage(), Toast.LENGTH_LONG).show();
            mAuth.signOut();
        }
    });

}

And part of the log:

10-09 22:13:10.971 27271-27271/com.example.radzik.recipes D/AndroidBash: **signIn:radzikjasiek@gmail.com**
10-09 22:13:11.061 27271-27385/com.example.radzik.recipes D/EGL_emulation: eglMakeCurrent: 0xa2f56080: ver 2 0 (tinfo 0xb40ad170)
10-09 22:13:11.085 27271-27385/com.example.radzik.recipes D/EGL_emulation: eglMakeCurrent: 0xa2f56080: ver 2 0 (tinfo 0xb40ad170)
10-09 22:13:11.110 27271-27385/com.example.radzik.recipes D/EGL_emulation: eglMakeCurrent: 0xa2f56080: ver 2 0 (tinfo 0xb40ad170)
10-09 22:13:11.124 27271-27385/com.example.radzik.recipes D/EGL_emulation: eglMakeCurrent: 0xa2f56080: ver 2 0 (tinfo 0xb40ad170)
10-09 22:13:11.146 27271-27385/com.example.radzik.recipes D/EGL_emulation: eglMakeCurrent: 0xa2f56080: ver 2 0 (tinfo 0xb40ad170)
10-09 22:13:11.168 27271-27385/com.example.radzik.recipes D/EGL_emulation: eglMakeCurrent: 0xa2f56080: ver 2 0 (tinfo 0xb40ad170)
10-09 22:13:11.296 27271-27385/com.example.radzik.recipes D/EGL_emulation: eglMakeCurrent: 0xa2f56080: ver 2 0 (tinfo 0xb40ad170)
10-09 22:13:11.481 27271-27385/com.example.radzik.recipes D/EGL_emulation: eglMakeCurrent: 0xa2f56080: ver 2 0 (tinfo 0xb40ad170)
10-09 22:13:11.498 27271-27385/com.example.radzik.recipes D/EGL_emulation: eglMakeCurrent: 0xa2f56080: ver 2 0 (tinfo 0xb40ad170)
10-09 22:13:11.843 27271-27283/com.example.radzik.recipes D/FirebaseAuth: Notifying id token listeners about user ( Z7aaBQR6GRMaQ35N22jQg2PRgau2 ).
10-09 22:13:11.843 27271-27283/com.example.radzik.recipes D/FirebaseAuth: Notifying auth state listeners about user ( Z7aaBQR6GRMaQ35N22jQg2PRgau2 ).
10-09 22:13:11.874 27271-27271/com.example.radzik.recipes D/FirebaseApp: Notifying auth state listeners.
10-09 22:13:11.875 27271-27271/com.example.radzik.recipes D/FirebaseApp: Notified 0 auth state listeners.
10-09 22:13:11.875 27271-27271/com.example.radzik.recipes D/AndroidBash: **onAuthStateChanged:signed_in:Z7aaBQR6GRMaQ35N22jQg2PRgau2**
10-09 22:13:11.875 27271-27271/com.example.radzik.recipes D/AndroidBash: signInWithEmail:onComplete:true
10-09 22:13:11.901 27271-27385/com.example.radzik.recipes D/EGL_emulation: eglMakeCurrent: 0xa2f56080: ver 2 0 (tinfo 0xb40ad170)
10-09 22:13:11.903 27271-27385/com.example.radzik.recipes E/Surface: getSlotFromBufferLocked: unknown buffer: 0x9d2abf00
10-09 22:13:11.914 27271-27940/com.example.radzik.recipes V/FA: Recording user engagement, ms: 11492
10-09 22:13:11.915 27271-27940/com.example.radzik.recipes V/FA: Using measurement service
10-09 22:13:11.915 27271-27940/com.example.radzik.recipes V/FA: Connecting to remote service
10-09 22:13:11.926 27271-27940/com.example.radzik.recipes V/FA: Activity paused, time: 14198714
10-09 22:13:11.930 27271-27940/com.example.radzik.recipes D/FA: Logging event (FE): user_engagement(_e), Bundle[{firebase_event_origin(_o)=auto, engagement_time_msec(_et)=11492, firebase_screen_class(_sc)=LoginActivity, firebase_screen_id(_si)=-2359265460650245341}]
10-09 22:13:11.970 27271-27271/com.example.radzik.recipes V/FA: onActivityCreated
10-09 22:13:11.980 27271-27271/com.example.radzik.recipes I/AppCompatViewInflater: app:theme is now deprecated. Please move to using android:theme instead.
10-09 22:13:11.984 27271-27940/com.example.radzik.recipes V/FA: Using measurement service
10-09 22:13:11.985 27271-27940/com.example.radzik.recipes V/FA: Connection attempt already in progress
10-09 22:13:12.077 27271-28499/com.example.radzik.recipes I/DynamiteModule: Considering local module com.google.android.gms.firebase_database:4 and remote module com.google.android.gms.firebase_database:6
10-09 22:13:12.077 27271-28499/com.example.radzik.recipes I/DynamiteModule: Selected remote version of com.google.android.gms.firebase_database, version >= 6
10-09 22:13:12.297 27271-27271/com.example.radzik.recipes I/TextToSpeech: Sucessfully bound to com.svox.pico
10-09 22:13:12.307 27271-27940/com.example.radzik.recipes V/FA: Using measurement service
10-09 22:13:12.307 27271-27940/com.example.radzik.recipes V/FA: Connection attempt already in progress
10-09 22:13:12.309 27271-27940/com.example.radzik.recipes D/FA: Logging event (FE): screen_view(_vs), Bundle[{firebase_event_origin(_o)=auto, firebase_previous_class(_pc)=LoginActivity, firebase_previous_id(_pi)=-2359265460650245341, firebase_screen_class(_sc)=MainActivity, firebase_screen_id(_si)=-2359265460650245340}]
10-09 22:13:12.318 27271-27271/com.example.radzik.recipes I/TextToSpeech: Connected to ComponentInfo{com.svox.pico/com.svox.pico.PicoService}
10-09 22:13:12.319 27271-27354/com.example.radzik.recipes I/TextToSpeech: Set up connection to ComponentInfo{com.svox.pico/com.svox.pico.PicoService}
10-09 22:13:12.324 27271-27940/com.example.radzik.recipes V/FA: Using measurement service
10-09 22:13:12.324 27271-27940/com.example.radzik.recipes V/FA: Connection attempt already in progress
10-09 22:13:12.324 27271-27940/com.example.radzik.recipes V/FA: Activity resumed, time: 14199108
10-09 22:13:12.383 27271-27385/com.example.radzik.recipes D/EGL_emulation: eglMakeCurrent: 0xa2f56080: ver 2 0 (tinfo 0xb40ad170)
10-09 22:13:12.478 27271-27940/com.example.radzik.recipes D/FA: Connected to remote service
10-09 22:13:12.478 27271-27940/com.example.radzik.recipes V/FA: Processing queued up service tasks: 4
10-09 22:13:12.491 27271-27370/com.example.radzik.recipes W/SyncTree: Listen at /users/Z7aaBQR6GRMaQ35N22jQg2PRgau2/name failed: FirebaseError: Permission denied
10-09 22:13:12.540 27271-27281/com.example.radzik.recipes I/art: Background partial concurrent mark sweep GC freed 7207(410KB) AllocSpace objects, 2(136KB) LOS objects, 6% free, 54MB/58MB, paused 16.082ms total 68.851ms
10-09 22:13:12.637 27271-27271/com.example.radzik.recipes W/art: Before Android 4.1, method int android.support.v7.widget.ListViewCompat.lookForSelectablePosition(int, boolean) would have incorrectly overridden the package-private method in android.widget.ListView
10-09 22:13:12.791 27271-27271/com.example.radzik.recipes D/FirebaseAuth: **Notifying id token listeners about a sign-out event.**
10-09 22:13:12.791 27271-27271/com.example.radzik.recipes D/FirebaseAuth: Notifying auth state listeners about a sign-out event.
10-09 22:13:12.903 27271-27271/com.example.radzik.recipes D/FirebaseApp: Notifying auth state listeners.
10-09 22:13:12.904 27271-27271/com.example.radzik.recipes D/FirebaseApp: Notified 1 auth state listeners.
10-09 22:13:12.904 27271-27271/com.example.radzik.recipes D/AndroidBash: **onAuthStateChanged:signed_out**
10-09 22:13:12.905 27271-27385/com.example.radzik.recipes E/Surface: getSlotFromBufferLocked: unknown buffer: 0x9d2ac5e0
10-09 22:13:13.146 27271-27385/com.example.radzik.recipes D/EGL_emulation: eglMakeCurrent: 0xa2f56080: ver 2 0 (tinfo 0xb40ad170)
10-09 22:13:13.178 27271-27385/com.example.radzik.recipes V/RenderScript: 0xa2702000 Launching thread(s), CPUs 2
10-09 22:13:13.215 27271-27385/com.example.radzik.recipes D/EGL_emulation: eglMakeCurrent: 0xa2f56080: ver 2 0 (tinfo 0xb40ad170)
10-09 22:13:13.450 27271-28499/com.example.radzik.recipes W/SyncTree: Listen at /users failed: DatabaseError: Permission denied
10-09 22:13:13.470 27271-28499/com.example.radzik.recipes W/SyncTree: Listen at /recipes failed: DatabaseError: Permission denied
10-09 22:13:13.478 27271-28499/com.example.radzik.recipes W/SyncTree: Listen at /photos_uploads failed: DatabaseError: Permission denied
10-09 22:13:13.486 27271-28499/com.example.radzik.recipes W/SyncTree: Listen at /cookbooks failed: DatabaseError: Permission denied
10-09 22:13:13.594 27271-28499/com.example.radzik.recipes W/SyncTree: Listen at /users/Z7aaBQR6GRMaQ35N22jQg2PRgau2/books failed: DatabaseError: Permission denied
10-09 22:13:13.613 27271-28499/com.example.radzik.recipes W/SyncTree: Listen at /recipes/Z7aaBQR6GRMaQ35N22jQg2PRgau2 failed: DatabaseError: Permission denied
10-09 22:13:16.296 27271-27385/com.example.radzik.recipes E/Surface: getSlotFromBufferLocked: unknown buffer: 0x9d2ac4a0
10-09 22:13:17.557 27271-27940/com.example.radzik.recipes V/FA: Inactivity, disconnecting from the service

I looked deeper into the problem and found the solution this morning. It's quite easy and I have no idea why I haven't came up with it earlier.

The problem was with the rules.

These are old rules:

    {
  "rules": {
    "recipes-309da": {
      "cookbooks": {
        ".read": "auth != null",
            ".write": "auth != null",
    },

    "recipes": {
        ".read": "auth != null",
            ".write": "auth != null",
    },

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

Method I used to create user was:

mRef.child("users").child(userId).setValue(user);

The result was obvious - access to /users was restricted to users, thus no user could effectively sign in to database...

I changed it and now it works perfectly fine. Below I put new, updated code. Great thanks for all help you provided me with.

{
  "rules": {
        "users": {
                "$uid": {
                    ".read": true,
                            ".write": true,

                    "books": {
                                ".read": "auth != null",
                        ".write": "auth != null",
                }
            } 
         },

        "recipes": {
          "$uid": {
            ".read": "auth != null",
                ".write": "auth != null",
          }   
        },

                "cookbooks": {
          ".read": "auth != null",
          ".write": "auth != null",
        }
    } 
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM