web-dev-qa-db-fra.com

Règles de sécurité Firestore: que se passe-t-il avec request.resource.data. <prop> lors de la mise à jour?

Mon équipe en a discuté récemment et ne semble pas pouvoir déterminer avec certitude le comportement réel/prévu:

Si vous avez une règle de sécurité comme la suivante:

match /categories/{document=**} {
    allow update: if request.auth.uid != null
    && request.resource.data.firstName is string
    && request.resource.data.lastName is string;
}

Et vous créez une instruction de mise à jour du frontend vers/categories/avec les données suivantes:

{
   firstName: 'A valid firstName'
}

La règle de sécurité est-elle alors censée réussir ou échouer?

Dans le documentation de référence , il est dit que

Les données fournies par le développeur sont présentées dans request.resource.data, qui est une carte contenant les champs et les valeurs. Les champs non fournis dans la demande qui existent dans la ressource sont ajoutés à request.resource.data

Questions connexes:

  1. Est-ce à dire que le succès/l'échec dépend des données existantes dans le nœud?
  2. Que se passe-t-il si quelqu'un essaie de mettre à jour avec des données non spécifiées dans la règle de sécurité, par exemple {age: 28}
  3. Quelle est la méthode recommandée pour valider les données de mise à jour?

Question 3 avec plus de détails (question de schéma) Supposons que vous ayez un modèle comme celui-ci:

interface Category {
  firstName: string;
  lastName: string;
  age?: int;
  groupId?: string;
}

Maintenant, nous créons une règle de sécurité comme celle-ci:

match /categories/{document=**} {
    allow update: if request.auth.uid != null
    && request.resource.data.firstName is string
    && request.resource.data.lastName is string;
    && request.resource.data.age is int;
    && request.resource.data.groupId is string;
}

Ensuite, nous avons le scénario suivant, si je comprends bien: enter image description here

Aucun de ces scénarios correspond bien aux propriétés facultatives. Parce que si vous devez fournir toutes les propriétés (comme dans le scénario 1), ce ne sont pas vraiment des propriétés facultatives. Et si vous ne les fournissez pas, comme dans le scénario 2, cela échoue.

Peut-être que je manque quelque chose ici, un guide de base sur la façon de valider les données avec des propriétés facultatives écrites dans Firestore?

Une règle de sécurité pour un paramètre facultatif, quelque chose comme ceci:

match /categories/{document=**} {
   allow update: if request.auth.uid != null
   && request.resource.data.firstName is string
   && request.resource.data.lastName is string;
   && request.resource.data.age is int; // ignore if NOT provided
   && request.resource.data.groupId is string; // ignore if NOT provided
}
15
DauleDK

La règle de sécurité est-elle alors censée réussir ou échouer?

Cette mise à jour réussira si le document mis à jour possède déjà un champ lastName et que ce champ est un string. (Je suppose que vous exécutez cette mise à jour pendant l'authentification afin que request.auth.uid != null Renvoie vrai)

Répondre aux questions connexes:

  1. Oui, parfois cela peut dépendre des données existantes sur le nœud.
  2. Si ce document a déjà un ensemble firstName et lastName, l'ajout du champ age réussira. Notez que la règle vérifie uniquement si ces 2 valeurs sont des chaînes. Il ne spécifie pas que le document ne peut pas avoir plus de 2 champs.
  3. Cette question semble un peu large (un peu comme un problème XY je dirais). Veuillez expliquer le type de validation de mise à jour que vous essayez de faire. Sur la base de vos questions, j'ai déjà une idée de ce que vous essayez, mais je veux être sûr à 100%.

Mise à jour :

Ce que j'ai compris de votre question mise à jour 3, c'est que vous ne souhaitez mettre à jour le document que si l'utilisateur a fourni à la fois le prénom et le nom. L'âge et groupId sont facultatifs.

Pour ce faire, vous pouvez vérifier si ce request.resource.data.firstName N'est pas déjà celui de la base de données en utilisant: resource.data.firstName != request.resource.data.firstName. Vos règles de sécurité devraient donc ressembler à ceci:

match /categories/{document=**} {
   allow update: if request.auth.uid != null
   && (request.resource.data.firstName is string && resource.data.firstName != request.resource.data.firstName)
   && (request.resource.data.lastName is string && resource.data.firstName != request.resource.data.firstName)
   && request.resource.data.age is int
   && request.resource.data.groupId is string
}

Maintenant avec ces règles, une mise à jour avec ces données échouera:

{
   firstName: 'A valid firstName'
}

Alors que ces 3 réussiront:

{
   firstName: 'A valid firstName',
   lastName: 'A valid lastName'
}

{
   firstName: 'A valid firstName',
   lastName: 'A valid lastName',
   age: 20
}

{
   firstName: 'A valid firstName',
   lastName: 'A valid lastName',
   age: 20,
   groupId: 'groupId'
}

Mise à jour 2: Pour avoir age et groupId comme champs facultatifs, utilisez l'opérateur OR et la fonction hasAll() pour vérifier si la demande a ces champs:

match /categories/{document=**} {
   allow update: if request.auth.uid != null
   && (request.resource.data.firstName is string && resource.data.firstName != request.resource.data.firstName)
   && (request.resource.data.lastName is string && resource.data.firstName != request.resource.data.firstName)
   || (request.resource.data.keys().hasAll(['age']) && request.resource.data.age is int)
   || (request.resource.data.keys().hasAll(['groupId']) && request.resource.data.groupId is string)
}