简体   繁体   English

身份验证后读取数据时,Firebase 权限被拒绝

[英]Firebase Permission denied when reading data after authentication

I am new to Firebase.我是 Firebase 的新手。 I authenticated the user using email and password -我使用电子邮件和密码对用户进行了身份验证 -

final Firebase ref = new Firebase("https://app.firebaseio.com");
ref.authWithPassword("app@firebaseio.com", "password", new Firebase.AuthResultHandler() {

    @Override
    public void onAuthenticated(AuthData authData) {
        System.out.println("User ID: " + authData.getUid());
        getData(ref);
    }

    @Override
    public void onAuthenticationError(FirebaseError firebaseError) {
    }
});

But after authentication when I am reading the data, I am getting Permission Denied .但是在我读取数据时进行身份验证后,我收到Permission Denied

private void getData(Query ref) {
    ref.addValueEventListener(new ValueEventListener() {

        @Override
        public void onDataChange(DataSnapshot snapshot) {
            System.out.println(snapshot.getValue());
        }

        @Override
        public void onCancelled(FirebaseError firebaseError) {
            System.out.println("The read failed: " + firebaseError.getMessage());
        }
    });
}

These are the Firebase rules.这些是 Firebase 规则。

{
    "rules": {
        "users": {
            "$uid": {
                ".read": "auth !== null && auth.provider === 'password'"
            }
        }
    }
}

Firebase's permission model only allows the user access to data that you explicitly give access to. Firebase 的权限模型只允许用户访问您明确授予访问权限的数据。 Since in your security rules, you only give access to /users/$uid , the user cannot read from root / .由于在您的安全规则中,您只能访问/users/$uid ,因此用户无法从 root /读取。 The Firebase documentation covers this under "rules cascade" . Firebase 文档在“规则级联”下对此进行了介绍。

You seem to want to use security rules to filter data, which is not possible with Firebase's security model.您似乎想使用安全规则来过滤数据,这在 Firebase 的安全模型中是不可能的。 See the section "rules are not filters" in the Firebase documentation as well as these previous questions and answers:请参阅 Firebase 文档中的“规则不是过滤器”部分以及这些先前的问题和答案:

The simplest solution is to allow read of the users node:最简单的解决方案是允许读取users节点:

{
    "rules": {
        "users": {
            ".read": "auth !== null && auth.provider === 'password'"
        }
    }
}

And then query on that level:然后在该级别查询:

getData(ref.child("users"));

I got this exception using a slightly different approach to read from my database, but this is how I solved the issue.我使用稍微不同的方法从我的数据库中读取数据,但这是我解决问题的方法。

First of all, my database rules looked liked this:首先,我的数据库规则看起来像这样:

{
"rules": {
  "student": {
    "$uid": {
      ".write": "auth != null && auth.uid == $uid",
      ".read": "auth != null && auth.uid == $uid"
      }
    }
  }
}

Earlier on, to write to to the student database, I used this code in my Activity:早些时候,为了写入学生数据库,我在我的活动中使用了以下代码:

 mAuthListener = new FirebaseAuth.AuthStateListener() {
        @Override
        public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
            user = firebaseAuth.getCurrentUser();
            if (user != null) {
                // User is signed in
                Log.e(TAG, "onAuthStateChanged:signed_in:" + user.getUid());
            } else {
                // User is signed out
                Log.e(TAG, "onAuthStateChanged:signed_out");
            }
            // ...
        }
    };
    ...
    Student student = new Student();
    student.setPhoneNumber("+23480547455343");
    student.setCountryOfOrigin("Nigeria");
    mDatabaseReference.child("student").child(user.getUid()).setValue(student).
                addOnCompleteListener(DetailsCaptureActivity.this, 
                                   new OnCompleteListener<Void>() {
     ...
     });

Notice how the child name (student) matches the child name in the firebase data rules?请注意子名称(学生)如何与 Firebase 数据规则中的子名称匹配?

Now to read the data of this user, I did this:现在要读取该用户的数据,我这样做了:

 //Set up an AuthStateListener that responds to changes in the user's sign-in state:
    mAuthListener = new FirebaseAuth.AuthStateListener() {
        @Override
        public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
            user = firebaseAuth.getCurrentUser();
            if (user != null) {

                   databaseReference = firebaseDatabase.getReference().child("student").child(user.getUid());
                   databaseReference.addValueEventListener(new ValueEventListener() {
                      @Override
                      public void onDataChange(DataSnapshot dataSnapshot) {
                          Student student = dataSnapshot.getValue(Student.class);
                          phoneNumberTextView.setText(student.getPhoneNumber());
                      }

                      @Override
                      public void onCancelled(DatabaseError databaseError) {

                          Log.e(TAG, databaseError.getMessage());
                      }
                  });

            } else {
                Log.e(TAG, "onAuthStateChanged:signed_out");
            }
        }
    };

I got the permission denied exception if I did only:如果我只这样做,我会得到许可被拒绝的异常:

databaseReference = firebaseDatabase.getReference().child(user.getUid());

The problem is that Firebase has a bug, that after authentication, you have to wait until user appears in the FirebaseAuth , and then you can use it.问题是 Firebase 有一个 bug,在认证之后,你必须等到用户出现在FirebaseAuth ,然后你才能使用它。

What I did is waited for it to appear, like我所做的就是等待它出现,比如

Observable.fromCallable(() -> signInImpl())
        .map(this::toFirebaseUser)
        .map(this::waitForUserToAppearInAuthenticator)
        .flatMap(this::doSomethingInDatabase);

Where在哪里

@NonNull
private FirebaseUser waitForUserToAppearInAuthenticator(@NonNull final FirebaseUser user) {
    final CountDownLatch cdl = new CountDownLatch(1);
    final FirebaseAuth.AuthStateListener l = firebaseAuth -> {
        final FirebaseUser cu = firebaseAuth.getCurrentUser();
        if (cu != null && user.getUid().equals(cu.getUid())) {
            cdl.countDown();
        }
    };
    mFirebaseAuth.addAuthStateListener(l);
    try {
        cdl.await(20, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    } finally {
        mFirebaseAuth.removeAuthStateListener(l);
    }

    return user;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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