Правило безопасности Firestore get() не работает
В firestore я хочу, чтобы пользователь имел доступ только к документу, если пользователь находится в teamid
упомянутой в документе. Теперь у меня есть другая коллекция, называемая teams
где у меня есть пользователи, сопоставленные как { user_id = true }
. Поэтому в правилах Firestore есть следующее:
return get(/databases/$(database)/documents/teams/$(resource.data.teamid)).data.approvedMembers[request.auth.uid] == true;
Теперь это правило не работает и не выполняет запрос, запрошенный в базу данных интерфейсом. Но когда я заменю $(resource.data.teamid)
моим фактическим значением teamid
следующим образом,
return get(/databases/$(database)/documents/teams/234234jk2jk34j23).data.approvedMembers[request.auth.uid] == true;
... он работает так, как ожидалось.
Теперь мой вопрос заключается в том, что я неправильно использую resource
или не поддерживается resource
в запросах get()
или exists()
в правилах Firestore?
Править
service cloud.firestore {
match /databases/{database}/documents {
function isTeamMember() {
return get(/databases/$(database)/documents/teams/$(resource.data.teamid)).data.approvedMembers[request.auth.uid] == true;
// return exists(/databases/$(database)/documents/teams/$(resource.data.teamid));
}
match /{document=**} {
allow read, write: if isTeamMember();
}
}
}
Если вы заметили правило с комментариями, exists()
также не работает в этом случае.
Ответы
Ответ 1
У вас есть этот match
:
match /{document=**} {
allow read, write: if isTeamMember();
}
Это будет соответствовать любому документу в базе данных. Это означает, что при вызове isTeamMember()
он не гарантирует, что resource
представляет собой team
документ. Если у вас есть подколлекции в teams
и пишите их, то resource
будет документ субколлекции.
Ответ 2
Спасибо, что обратились к Твиттеру. После нашего чата, вот вывод:
Запрос документов с использованием правила безопасности
Вы не можете использовать правило безопасности в качестве фильтра. Чтобы заставить это работать, вы также должны добавить .where('teamid', '==', yourTeamId)
Вы подтвердили, что это работает для вас, но вы не всегда хотите ограничить одну команду
Использование пользовательских требований
Вы можете настроить пользовательские требования в токенах аутентификации. Вот пример того, как их устанавливать, и они используют их в ваших правилах
Настройка пользовательских требований
Для этого вам потребуется использовать SDK Admin.
auth = firebase.auth();
const userId = 'exampleUserId';
const customClaims = {teams: {myTeam1: true, myTeam2: true}};
return auth.setCustomUserClaims(userId, customClaims)
.then(() => {
console.log('Custom claim created');
return auth.getUser(userId);
})
.then(userRecord => {
console.log('name: ${userRecord.displayName}');
console.log('emailVerified: ${userRecord.emailVerified}');
console.log('email: ${userRecord.email}');
console.log('emailVerified: ${userRecord.emailVerified}');
console.log('phoneNumber: ${userRecord.phoneNumber}');
console.log('photoURL: ${userRecord.photoURL}');
console.log('disabled: ${userRecord.disabled}');
console.log('customClaims: ${JSON.stringify(userRecord.customClaims)}');
})
.catch(err => {
console.error(err);
});
Применение правила безопасности
allow read, write: if request.auth.token.teams.$(resource.data.teamId) == true;
Я все еще не уверен на 100%, что это также не потребует от вас фильтрации от teamid
. Пожалуйста, проверьте его и верните.