【问题标题】:Firebase Permission denied when reading data after authentication身份验证后读取数据时,Firebase 权限被拒绝
【发布时间】:2016-02-09 23:09:18
【问题描述】:

我是 Firebase 的新手。我使用电子邮件和密码对用户进行了身份验证 -

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) {
    }
});

但在我读取数据时经过身份验证后,我得到了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());
        }
    });
}

这些是 Firebase 规则。

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

【问题讨论】:

    标签: android firebase firebase-security firebase-realtime-database


    【解决方案1】:

    Firebase 的权限模型仅允许用户访问您明确授予访问权限的数据。由于在您的安全规则中,您只授予对/users/$uid 的访问权限,因此用户无法从根/ 读取。 Firebase 文档在"rules cascade" 下对此进行了介绍。

    您似乎想使用安全规则来过滤数据,而这在 Firebase 的安全模型中是不可能的。请参阅 Firebase 文档中的 "rules are not filters" 部分以及这些先前的问题和答案:

    最简单的解决方案是允许读取users 节点:

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

    然后在那个级别上查询:

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

    【讨论】:

    • 关于规则级联的好点,感谢您分享有关规则的更多信息。我还想提到另一个使用 identical firebase sdks 的修复,这对我有用。
    【解决方案2】:

    我使用稍微不同的方法从我的数据库中读取这个异常,但这就是我解决问题的方法。

    首先,我的数据库规则看起来像这样:

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

    早些时候,为了写入学生数据库,我在我的活动中使用了这段代码:

     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>() {
         ...
         });
    

    注意子名(学生)如何与 Firebase 数据规则中的子名匹配?

    现在要读取这个用户的数据,我这样做了:

     //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");
                }
            }
        };
    

    如果我这样做了,我得到了权限被拒绝的异常:

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

    【讨论】:

      【解决方案3】:

      问题是Firebase有一个bug,就是认证后,必须等到FirebaseAuth出现用户,然后才能使用。

      我所做的就是等待它出现,就像

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

      在哪里

      @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;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-11-07
        • 2018-08-21
        • 2017-12-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多