gpt4 book ai didi

firebase - 使用安全规则限制 child /现场访问

转载 作者:行者123 更新时间:2023-12-01 18:44:21 26 4
gpt4 key购买 nike

我正在编写一个应用程序,允许用户提交提名,这些提名在显示给其他用户之前会经过审核。这需要一些限制,到目前为止我尚未成功地使用安全规则实现:

  1. 隐藏所有尚未获得批准的提名
  2. 隐藏提交时的私有(private)字段(电话、批准状态、创建日期等)

我当前的规则如下:

{
"rules": {
"nominations": {
".read": true,

"$nominationId": {
".read": "data.child('state').val() == 'approved' || auth != null", // Only read approved nominations if not authenticated
".write": "!data.exists()", // Only allow new nominations to be created

"phone": {
".read": "auth != null" // Only allow authenticated users to read phone number
},

"state": {
".read": "auth != null", // Only allow authenticated users to read approval state
".write": "auth != null" // Only allow authenticated users to change state
}
}
}
}
}

子规则(例如 $nomination)不会阻止从父级读取整个子级。如果我在 https://my.firebaseio.com/nominations 上监听 child_added,即使设置了上述安全规则,它也会愉快地返回所有子项及其所有数据。

我目前的解决方法是保留一个名为approved的单独节点,并在有人批准或拒绝提名时简单地在列表之间移动数据,但这似乎是一种非常糟糕的方法。

更新

根据 Michael Lehenbauer 的精彩评论,我以最小的努力重新实现了最初的想法。

新的数据结构如下:

my-firebase
|
`- nominations
|
`- entries
| |
| `- private
| `- public
|
`- status
|
`- pending
`- approved
`- rejected

每项提名都存储在entries下,其中电话号码、电子邮件等私有(private)数据存储在private下,公开可见的数据存储在public下>.

更新后的规则如下:

{
"rules": {
"nominations": {
"entries": {
"$id": {
".write": "!data.exists()",

"public": {
".read": true,
},

"private": {
".read": "auth != null"
}
}
},

"status": {
"pending": {
".read": "auth != null",

"$id": {
".write": "root.child('nominations/entries').child($id).exists() && (auth != null || newData.val() == true)"
}
},

"approved": {
".read": true,

"$id": {
".write": "root.child('nominations/entries').child($id).exists() && auth != null"
}
},


"rejected": {
".read": "auth != null",

"$id": {
".write": "root.child('nominations/entries').child($id).exists() && auth != null"
}
}
}
}
}
}

以及 JavaScript 实现:

var db = new Firebase('https://my.firebaseio.com')
var nominations = db.child('nominations')

var entries = nominations.child('entries')

var status = nominations.child('status')
var pending = status.child('pending')
var approved = status.child('approved')
var rejected = status.child('rejected')

// Create nomination via form input (not shown)
var createNomination = function() {
var data = {
public: {
name: 'Foo',
age: 20
},

private: {
createdAt: new Date().getTime(),
phone: 123456
}
}

var nomination = entries.push()
nomination.setWithPriority(data, data.private.createdAt)

pending.child(nomination.name()).set(true)
}

// Retrieve current nomination status
var getStatus = function(id, callback) {
approved.child(id).once('value', function(snapshot) {
if (snapshot.val()) {
callback(id, 'approved')
} else {
rejected.child(id).once('value', function(snapshot) {
callback(id, snapshot.val() ? 'rejected' : 'pending')
})
}
})
}

// Change status of nomination
var changeStatus = function(id, from, to) {
status.child(from).child(id).remove()
status.child(to).child(id).set(true)
}

我正在努力实现的唯一部分是处理状态更改,我当前的方法肯定可以改进:

_.each([pending, approved, rejected], function(status) {
status.on('child_added', function(snapshot) {
$('#' + snapshot.name()).removeClass('pending approved rejected').addClass(status.name())
})
})

我计划在提名/状态上使用child_changed,但我一直无法让它可靠地工作。

最佳答案

加藤是对的。重要的是要了解安全规则永远不会过滤数据。对于任何位置,您要么能够读取所有数据(包括其子数据),要么无法读取任何数据。因此,就您的规则而言,在“提名”下设置“.read”:true 会否定您的所有其他规则。

所以我在这里推荐的方法是拥有 3 个列表。一份包含提名数据,一份包含已批准提名的列表,一份包含待定提名的列表。

你的规则可能是这样的:

{
"rules": {
// The actual nominations. Each will be stored with a unique ID.
"nominations": {
"$id": {
".write": "!data.exists()", // anybody can create new nominations, but not overwrite existing ones.
"public_data": {
".read": true // everybody can read the public data.
},
"phone": {
".read": "auth != null", // only authenticated users can read the phone number.
}
}
},
"approved_list": {
".read": true, // everybody can read the approved nominations list.
"$id": {
// Authenticated users can add the id of a nomination to the approved list
// by creating a child with the nomination id as the name and true as the value.
".write": "auth != null && root.child('nominations').child($id).exists() && newData.val() == true"
}
},
"pending_list": {
".read": "auth != null", // Only authenticated users can read the pending list.
"$id": {
// Any user can add a nomination to the pending list, to be moderated by
// an authenticated user (who can then delete it from this list).
".write": "root.child('nominations').child($id).exists() && (newData.val() == true || auth != null)"
}
}
}
}

未经身份验证的用户可以通过以下方式添加新提名:

var id = ref.child('nominations').push({ public_data: "whatever", phone: "555-1234" });
ref.child('pending_list').child(id).set(true);

经过身份验证的用户可以通过以下方式批准消息:

ref.child('pending_list').child(id).remove();
ref.child('approved_list').child(id).set(true);

要呈现已批准和待处理的列表,您可以使用类似以下的代码:

ref.child('approved_list').on('child_added', function(childSnapshot) {
var nominationId = childSnapshot.name();
ref.child('nominations').child(nominationId).child('public_data').on('value', function(nominationDataSnap) {
console.log(nominationDataSnap.val());
});
});

通过这种方式,您可以使用approved_list和pending_list作为可以枚举的轻量级列表(分别由未经身份验证和经过身份验证的用户),并将所有实际提名数据存储在提名列表中(没有人可以直接枚举)。

关于firebase - 使用安全规则限制 child /现场访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14296625/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com