私は、他のユーザーに表示される前にモデレートされた推薦をユーザーが送信できるようにするアプリを作成しています。これには、これまでセキュリティ ルールでの実装に失敗してきた多くの制限が必要です。
- まだ承認されていない推薦を非表示にする
- 送信から非公開フィールドを非表示にする (電話番号、承認ステータス、作成日など)
私の現在のルールは次のとおりです。
{
"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
、公的に閲覧可能なデータは の下に保存され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
onを使用する予定nominations/status
でしたが、確実に動作させることができませんでした。