В моих правилах безопасности я делаю get()
для userDoc
.
Если do c не существует, get()
должен вернуть null
(cf документация ), и правило должно разрешать запрос (если do c существует, то правило должно разрешать, только если do c имеет правильное поле version
)
Проблема в том, что правила отклоняют создание первого документа при работе (= когда userDo c не существует), но они работают, когда я тестирую их с помощью инструмента тестирования
Я воспроизводю ту же ошибку с эмулятором, поэтому я смог использовать средство проверки правил и заметил, что get()
выдает ошибку вместо того, чтобы возвращать значение null
(несмотря на то, что правильно сформированный аргумент). Это согласуется с тем фактом, что в продукте у меня нет denied request
, а только error request
в консоли.
![Security Rules analyzer screenshot](https://i.stack.imgur.com/pmjqF.png)
Полная функция выглядит следующим образом:
function resourceVersionIsCompatible(resourceVersion) {
let userDoc = get(/databases/$(database)/documents/users/$(userId));
let serverVersion = userDoc != null && 'version' in userDoc.data ? int(string(userDoc.data.version).split('\\.')[0]) : 0;
return (serverVersion == 0) || (resourceVersion == serverVersion);
}
Если я заменю userDoc != null
на false
, тогда он будет работать хорошо (я могу создать первый документ, который инициализирует пользователя Do c благодаря облачная функция. А затем я могу восстановить обычные правила для успешного создания последующих документов с проверкой рабочей версии).
Полные правила приведены ниже:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Everything is disallowed if not specifically allowed after
match /{document=**} {
allow read, write: if false;
}
match /users/{userId} {
allow read: if request.auth.uid == userId;
allow write: if false;
match /{collection}/{documentId} {
function resourceIsValid(resourceVersion) {
return resourceVersion <= 2 && {
'version-1': (collection == 'interactions' || collection == 'contacts'),
'version-2': (collection == 'events' || collection == 'contacts')
}['version-' + string(resourceVersion)];
}
function resourceVersionIsCompatible(resourceVersion) {
let userDoc = get(/databases/$(database)/documents/users/$(userId));
let serverVersion = userDoc != null && 'version' in userDoc.data ? int(string(userDoc.data.version).split('\\.')[0]) : 0;
// We allow the request if the resourceVersion is the same major than the serverVersion
// of if there is no serverVersion (then a cloud function will initiate it based on the doc version)
return (serverVersion == 0) || (resourceVersion == serverVersion);
}
function creationAllowed() {
let resourceVersionMajor = 'v' in request.resource.data ? int(string(request.resource.data.v).split('\\.')[0]) : 1;
return request.auth.uid == userId
&& resourceIsValid(resourceVersionMajor)
&& resourceVersionIsCompatible(resourceVersionMajor);
}
allow read: if request.auth.uid == userId;
allow delete: if request.auth.uid == userId;
allow create, update: if creationAllowed();
}
}
}
}