Firebase 实时数据库规则

Posted

技术标签:

【中文标题】Firebase 实时数据库规则【英文标题】:Firebase real-time database rules 【发布时间】:2021-01-31 18:42:05 【问题描述】:

这是我的示例数据库:


  "referrals" : 
    "Nr7sS4xV1fO59wjCqbEabLlK8RF3" : 
      "16-10-2020" : 
        "-MJhjQddWdWDImj98Sov" : 
          "city" : "hyhy",
          "name" : "mmmm",
          "number" : "03058852844",
          "remarks" : "pg"
        ,
        "-MJhmeRiqeXskncHJF61" : 
          "city" : "vsva",
          "name" : "yhyh",
          "number" : "02089453882",
          "remarks" : "pg"
        
      ,
      "total_referrals" : 2
    ,
    "jpeoZQAPdZY4yEt8yGifGZi4U4r1" : 
      "16-10-2020" : 
        "-MJlzrS8xX8MGN1ar9uw" : 
          "city" : "lahore",
          "name" : "khursand",
          "number" : "03014181394",
          "remarks" : "paid"
        ,
        "-MJm-LFhEEMBzBPRftlC" : 
          "city" : "lahore",
          "name" : "khursand",
          "number" : "03014141111",
          "remarks" : "pg"
        
      ,
      "total_referrals" : 2
    
  ,
  "users" : 
    "Nr7sS4xV1fO59wjCqbEabLlK8RF3" : 
      "account_status" : "Level 1",
      "current_balance" : "0",
      "isBan" : false,
      "paid_referrals" : "0",
      "total_balance" : "0",
      "total_withdraw" : "0"
    ,
    "jpeoZQAPdZY4yEt8yGifGZi4U4r1" : 
      "account_status" : "Level 1",
      "current_balance" : "0",
      "paid_referrals" : "0",
      "total_balance" : "0",
      "total_withdraw" : "0"
    
  ,
  "withdraw_details" : 
    "Nr7sS4xV1fO59wjCqbEabLlK8RF3" : 
      "-MJMgVd3TuWYjdGSd-FY" : 
        "amount" : "600",
        "date" : "11/10/2020",
        "method" : "Easypaisa",
        "number" : "03058853833",
        "tid" : "90124678573"
      
    ,
    "jpeoZQAPdZY4yEt8yGifGZi4U4r1" : 
      "-MJm7SfTwWafae85ayRq" : 
        "amount" : "600",
        "date" : "11/10/2020",
        "method" : "Easypaisa",
        "number" : "03494628929",
        "tid" : "90124678573"
      
    
  

这是我尝试在控制台中设置的数据库规则:


  "rules": 
    "users":
      "$user_id":
        ".read": "$user_id == auth.uid && auth != null", // only owner or authenticated user can read
        ".write": false // No-one can write
          
      
    ,
      
    "withdraw_details":
      "$user_id":
        ".read": "$user_id == auth.uid && auth != null",// only owner or authenticated user can read
        ".write": false // No-one can write
      
    ,
        
    "referrals": 
      "$user_id": 
        ".read": "$user_id == auth.uid && auth != null", // same as above
        ".write": "$user_id == auth.uid && auth != null", // owner and authenticated can write
          "$date": 
            // children should be only these
            ".validate": "newData.hasChildren(['name', 'number', 'city', 'remarks'])",
              // you can see further validation rules below
            "name": ".validate": "newData.isString() && newData.val().length <= 30",
            "number": ".validate": "newData.isNumber() && newData.val().length == 11",
            "city": ".validate": "newData.isString() && newData.val().length <= 20",
            "remarks": ".validate": "newData.isString() && newData.val().length <= 15",
            
              // any other child should be rejected
            "$other": ".validate": false
            
          
      
      
  

现在我不知道我在这里做错了什么,因为每次我尝试读取任何孩子时都会引发 “Permission denied” 错误。

喜欢下面的用户详细信息请求

private void getDetails() 
    databaseReference.child("users").addListenerForSingleValueEvent(new ValueEventListener() 
        @Override
        public void onDataChange(@NonNull DataSnapshot snapshot) 

            if (snapshot.hasChild(mAuth.getCurrentUser().getUid())) 

                AccountDetails accountDetails = snapshot
                        .child(mAuth.getCurrentUser().getUid())
                        .getValue(AccountDetails.class);

                setValuesToTextViews(
                        accountDetails.getTotal_balance(),
                        accountDetails.getTotal_withdraw(),
                        accountDetails.getCurrent_balance(),
                        accountDetails.getAccount_status(),
                        accountDetails.getPaid_referrals(),
                        accountDetails.getTotal_referrals()
                );
             
            
        

        @Override
        public void onCancelled(@NonNull DatabaseError error) 
            Log.w(TAG, "onCancelled: " + error.toException());

            Toast.makeText(getActivity(), error.getMessage(), Toast.LENGTH_SHORT).show();
        
    );

此外,进一步澄清,我希望 /users/uid/ && /withdraw_details/uid/ 只能由其所有者读取,并且 auth 不应为空。并且应该拒绝对这些位置的写访问。

/referrals/uid/ 位置应该对其所有者具有读写权限,并具有某些标准和验证,如您在上面的数据库规则中所见。

【问题讨论】:

【参考方案1】:

安全规则本身不会过滤数据。相反,它们只是强制您对数据库执行的任何操作都是允许的。

因此,在您的代码中,您将侦听器附加到 /users

databaseReference.child("users").addListenerForSingleValueEvent(new ValueEventListener() 

执行此操作时,规则引擎会检查此用户是否具有对 /users 的读取权限。由于没有人对/users 具有读取权限,因此它拒绝了该操作。


您想要做的是读取特定用户的节点:

databaseReference.child("users").child(mAuth.getCurrentUser().getUid()).addListenerForSingleValueEvent(new ValueEventListener() 
    @Override
    public void onDataChange(@NonNull DataSnapshot snapshot) 
        AccountDetails accountDetails = snapshot.getValue(AccountDetails.class);

        setValuesToTextViews(
                accountDetails.getTotal_balance(),
                accountDetails.getTotal_withdraw(),
                accountDetails.getCurrent_balance(),
                accountDetails.getAccount_status(),
                accountDetails.getPaid_referrals(),
                accountDetails.getTotal_referrals()
        );
     
    ...

有关这方面的更多信息,请参阅 rules are not filters 上的 Firebase 文档,这些 search results 关于该主题,例如:Restricting child/field access with security rules

【讨论】:

为什么这个写操作失败了? databaseReference.child("referrals").child(mAuth.getCurrentUser().getUid()).child(utils.getDate(getActivity())).push().setValue(details); 如果没有看到您如何填充 details,这很难说。我建议使用新的MCVE 发布一个新问题。

以上是关于Firebase 实时数据库规则的主要内容,如果未能解决你的问题,请参考以下文章

Firebase 实时数据库规则被拒绝权限

如何在firebase实时数据库中编写规则?

Firebase 实时规则如何检查具有 AutoID 的节点是不是包含正确的数据

如何在firebase实时数据库规则中设置变量

我们如何为 Firebase 存储编写依赖于 Firebase 实时数据库中的值的安全规则? [复制]

Firebase 实时电话数据库安全规则