Firebase实时数据库规则在前端不起作用

时间:2020-10-15 16:07:40

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

特定TLDR:规则".read": "auth != null && data.child('userEmail').val() === root.child('users').child(auth.uid).child('email').val()"应在应用程序中按预期工作。

我已经按照文档进行操作,并且在规则规则下进行了测试,因此我认为这与我进行身份验证的方式有关吗?我将在下面提供信息,希望有人能尽快回答。

实时数据库结构:

"db-name": {
  "units": {
    0: {
      "serial": "002",
      "userEmail": "s@gmail.com"
    },
    1: {
      "serial": "001",
      "userEmail": "r@gmail.com"
    }
  },
  "users": {
    "R6nlZ...": {
      "email": "r@gmail.com"
    },
    "qwerty...": {
      "email": "s@gmail.com"
    }
  }
}

规则对象:

{
  "rules": {
    // ".read": "now < 1604037600000",  // 2020-10-30
    // ".write": "now < 1604037600000",  // 2020-10-30
    "units": {
      ".indexOn": "userEmail",
      "$key": {
        ".read": "auth != null && data.child('userEmail').val() === root.child('users').child(auth.uid).child('email').val()",
        ".write" : "auth != null && data.child('userEmail').val() === root.child('users').child(auth.uid).child('email').val()"
      }
    },
    "users": {
      "$uid": {
        ".read": "$uid === auth.uid",
        ".write": "$uid === auth.uid"
      }
    }
  }
}

规则测试: 模拟类型:读取 位置:https:db-name.firebaseio.com/units/1 阿姨:是的 提供者:匿名 UID:R6nlZ ... 结果:允许模拟读取

如果我尝试获取/units/0,我会被拒绝,这是我的期望,因为这是当前授权用户无权查看的unit

现在,如果我使用普通的javascript进行操作,则不会获得与Firebase控制台中的“规则游乐场”相同的结果。

<!-- Add the entire Firebase JavaScript SDK -->
    <script src="https://www.gstatic.com/firebasejs/7.24.0/firebase.js"></script>

    <script>
    // import * as firebase from "firebase";
    var firebaseConfig = {
      apiKey: "...",
        authDomain: "...",
        databaseURL: "...",
        projectId: "...",
        storageBucket: "...",
        messagingSenderId: "...",
        appId: "..."
    };
    // Initialize Firebase
    firebase.initializeApp(firebaseConfig);

    var email = 'r@gmail.com';
    var password = '123456';
    // Sign in existing user
    firebase.auth().signInWithEmailAndPassword(email, password).then(function() {
      console.log('Signed in as: ' + firebase.auth().currentUser.email);

      var dbUnits = firebase.database().ref().child('units').orderByChild('userEmail').equalTo(firebase.auth().currentUser.email);
      var getUnitsDetails = function() {
        return dbUnits.once('value').then(function(snapshot) {
          snapshot.val() ?
          Object.entries(snapshot.val()).map((unit) => {
            return (
              console.log('Serial number of unit: ' + unit[1].serial + ' & Owner of unit: ' + unit[1].userEmail)
            )
          })
          :
          console.log('no units found for that user bro')

        })
      }
      console.log(getUnitsDetails());


    }).catch(function(error) {
      console.log(error);
    });

当我按照粘贴的规则设置了Firebase权限时,用户r@gmail.com看不到任何单位。如果我让读取权限完全打开(不是我想要的),则该用户可以看到其单位。

对我来说这没有意义,因为我认为auth.uid是Firebase在用户登录时可以看到的内容,无论他们使用哪种登录类型。

2 个答案:

答案 0 :(得分:1)

您的规则不允许此查询:

firebase.database().ref().child('units').orderByChild('userEmail').equalTo(firebase.auth().currentUser.email);

为使此查询正常工作,用户需要具有对/units的读取权限。由于您没有在.read上声明任何/units规则,因此查询被拒绝。

您似乎认为规则将过滤数据以仅返回用户应有权访问的数据,但事实并非如此。如Firebase文档所述:rules are not filters

但是security rules can be used on combination with queries是为了安全地允许查询数据。

在您的情况下,看起来像这样:

{
  "rules": {
    "units": {
      ".read": "auth.uid != null &&
                query.orderByChild == 'userEmail' &&
                query.equalTo == auth.token.email"
      ...

现在将允许您的查询,而其他/更广泛的/users读操作将被拒绝。

答案 1 :(得分:0)

"$key": {
        ".read":   "auth !== null && root.child('users').hasChild(auth.uid)",
        ".write" : "auth !== null && root.child('users').hasChild(auth.uid)"
}

这样写,用户集中存在的任何用户都可以访问“单位”

或者,您可以使用该用户的uid进行收集,并将密钥与他的uid匹配以进行访问