Переменная правил Firebase, не соответствующая строке

#firebase #google-cloud-firestore #firebase-security

# #firebase #google-cloud-firestore #firebase-безопасность

Вопрос:

итак, я пытаюсь сопоставить адрес электронной почты пользователя с именем коллекции, как показано ниже в моих правилах Firestore:

 rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {  
    match /users/{userEmail} {
      allow read: if request.auth.token.email.matches(userEmail);      
    }
  }
}
 

Я знаю, что не рекомендуется устанавливать идентификаторы коллекции в качестве электронных писем, но, пожалуйста, предположите, что это любая строка здесь. Вышесказанное не работает. однако, если я request.auth.token.email.matches(userEmail) заменю request.auth.token.email.matches("myemail@gmail.com") его, он будет работать нормально.

введите описание изображения здесь

Выше у меня есть один документ в моей коллекции пользователей с id = myemail@gmail.com , так почему он не соответствует, когда я использую userEmail переменную, но будет соответствовать, если я использую «myemail@gmail.com » струна?

Дополнительная информация: запрос к /getAccountInfo вам можно просмотреть myemail@gmail.com как электронное письмо введите описание изображения здесь

Код приложения

Я использовал Vuexfire для привязки firestore. store/index.js

 bindUsers: firestoreAction(({bindFirestoreRef}) => {  
    return bindFirestoreRef("users", db.collection("users")
    .where('email', '==', 'myemail@gmail.com');
}),
 

App.vue

 async mounted() {
    if (firebase.auth.currentUser) {
        // Bind Vuexfire after if/when user exists to capture Firestore changes
        await this.$store.dispatch("bindUsers");
    }
}

 

Комментарии:

1. Правила безопасности сами по себе ничего не делают. Они имеют смысл только в сочетании с конкретными запросами, поступающими из веб-или мобильного приложения. Пожалуйста, отредактируйте свой вопрос, чтобы показать этот код, а также продемонстрировать (возможно, путем регистрации), что пользователь вошел в систему во время запроса с правильным адресом электронной почты.

2. @DougStevenson Я обновил свой скриншот выше. Если request.auth.token.email.matches("myemail@gmail.com") работает, то разве это не подтвердит, что у меня есть авторизация пользователя при загрузке моего приложения? Я получаю только тогда, когда я заменяю userEmail FirebaseError: Missing or insufficient permissions. на, и вы можете видеть на моем скриншоте имя документа myemail@gmail.com … разве ей не нравится @ maybe ?

3. Нам нужен код клиентского приложения, который выполняет запрос, как я описал в первом комментарии. Скриншот не рассказывает всей истории.

4. Я использую Vuexfire для привязки к моей коллекции, здесь . Я запускаю привязку только после того, как мое приложение смонтировано и if (firebase.auth.currentUser) . Я все еще не понимаю, почему это работает, если я обновляю правила для использования «myemail@gmail.com » строка, но не переменная {user}? << как это может сработать, если это проблема с «кодом клиентского приложения», учитывая, что единственным документом в коллекции является «myemail@gmail.com «?

5. Я не думаю, что вы можете использовать переменную «userEmail» непосредственно из строки «match / users / {userEmail}» (не уверен на 100%, но это может быть причиной того, что ваше текущее значение userEmail недопустимо.

Ответ №1:

Ваш запрос фильтруется по свойству документа с именем email (а не по его идентификатору):

 return bindFirestoreRef("users", db.collection("users")
.where('email', '==', 'myemail@gmail.com');
 

Это не имеет никакого отношения к токену электронной почты в учетной записи пользователя Firebase Auth. Вы вообще не показали, что у вас есть свойство электронной почты в документе — все, что у вас есть, это документ с идентификатором, который содержит адрес электронной почты.

В конечном итоге ваш запрос должен соответствовать правилу, которое ограничивает запрос. Это означает, что вам нужен какой-то способ явной фильтрации на клиенте таким образом, чтобы он соответствовал ограничениям правила. Это означает, что вам придется использовать get() запрос типа для конкретного документа с идентификатором, а не запрос коллекции, который требует фильтрации с помощью предложения where .

Комментарии:

1. Во-первых, спасибо за вашу помощь и терпение 🙂 Во-вторых… Я думаю, что это волшебная деталь, которую мне не хватало, но позвольте мне подтвердить, что я правильно понял. Чтобы фильтровать документы в коллекции с помощью .where(), вам понадобится доступ ко всем документам, чтобы .where() мог «заглянуть внутрь каждого»?

2. Во всех случаях ваши фильтры запросов должны соответствовать ограничениям правил. Правила не будут фильтровать результаты для вас. Это описано в документации . Если ваш запрос может соответствовать любому документу, который запрещен правилами, тогда весь запрос завершится ошибкой. Поскольку ваши правила разрешают пользователю доступ только к одному документу, который соответствует их адресу электронной почты, ваш запрос должен пытаться получить только один документ, и ничего больше.

3. Поскольку у меня есть один документ в моей коллекции, я мог бы исключить мой .where() все вместе (и понятные правила не являются фильтрами). С моим ЕДИНСТВЕННЫМ документом в моей коллекции это правило работает: if request.auth.token.email.matches("myemail@gmail.com"); и это не request.auth.token.email.matches(userEmail); << Это для меня все еще сбивает с толку

4. Не имеет значения, сколько документов в коллекции. Правила по-прежнему не будут принимать запросы, для которых требуется фильтр. Он не будет проверять каждую из них — это не будет масштабироваться, и, по сути, это то, что фильтр должен был бы делать в любом случае.


Ответ №2:

Я могу ошибаться, но похоже, что вы пишете свое правило скорее как фильтр, чем как правило безопасности.

@DougStevenson будет знать намного лучше меня, но если вы жестко запрограммируете строковое значение, Firestore сможет явно определить, будет ли это правило успешным или неудачным. Но если вы используете переменную, то я считаю, что Firestore определяет, будет ли правило возвращать true или false в целом, а не в конкретных случаях выполнения. В этом случае правило должно вернуться false , поскольку будут строки, которые не пройдут тест.

Похоже, вы пытаетесь использовать свое правило для фильтрации строк. Правила Firestore так не работают.

Как предлагает Doug, вы должны показать нам некоторый код на стороне клиента, который вы используете для доступа к этой коллекции, чтобы мы могли определить, попадает ли код в ловушку «правило, пытающееся быть фильтром».

Комментарии:

1. Я обновил свой первоначальный комментарий, указав, как я привязываюсь к Firestore. Я понимаю, что правила Firestore не применяют фильтрацию, но я пытаюсь сделать это как часть моего запроса, чтобы отфильтрованный запрос соответствовал правилам для этого пользователя. Однако мой тестовый пример в моем комментарии представляет собой один документ (так что все или ничего). И мои правила работают нормально, если я жестко задаю идентификатор документа: «myemail@gmail.com » но не будет работать, если я использую переменную documentId: «{userEmail}» (где используется только document in users myemail@gmail.com ). Что еще я мог запрашивать у приложения, что могло бы привести к разрыву этого 1-1?