Catch up on highlights from Firebase at Google I/O 2023. Learn more

Linguaggio delle regole di sicurezza

Le regole di sicurezza di Firebase sfruttano linguaggi flessibili, potenti e personalizzati che supportano un'ampia gamma di complessità e granularità. Puoi rendere le tue regole specifiche o generali come ha senso per la tua app. Le regole del database in tempo reale utilizzano una sintassi simile a JavaScript in una struttura JSON. Le regole di Cloud Firestore e Cloud Storage utilizzano un linguaggio basato sul Common Expression Language (CEL) , che si basa su CEL con le istruzioni match e allow che supportano l'accesso concesso in modo condizionale.

Poiché si tratta di lingue personalizzate, tuttavia, esiste una curva di apprendimento. Usa questa guida per comprendere meglio il linguaggio delle regole man mano che approfondisci regole più complesse.

Seleziona un prodotto per saperne di più sulle sue regole.

Struttura basilare

CloudFirestore

Le regole di sicurezza di Firebase in Cloud Firestore e Cloud Storage utilizzano la struttura e la sintassi seguenti:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

I seguenti concetti chiave sono importanti da comprendere durante la creazione delle regole:

  • Richiesta: il metodo o i metodi richiamati nell'istruzione allow . Questi sono metodi che stai permettendo di eseguire. I metodi standard sono: get , list , create , update e delete . I metodi pratici read e write consentono un ampio accesso in lettura e scrittura sul database o sul percorso di archiviazione specificato.
  • Percorso: il database o il percorso di archiviazione, rappresentato come percorso URI.
  • Regola: l'istruzione allow , che include una condizione che consente una richiesta se restituisce true.

Ciascuno di questi concetti è descritto più dettagliatamente di seguito.

Archiviazione cloud

Le regole di sicurezza di Firebase in Cloud Firestore e Cloud Storage utilizzano la struttura e la sintassi seguenti:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

I seguenti concetti chiave sono importanti da comprendere durante la creazione delle regole:

  • Richiesta: il metodo o i metodi richiamati nell'istruzione allow . Questi sono metodi che stai permettendo di eseguire. I metodi standard sono: get , list , create , update e delete . I metodi pratici read e write consentono un ampio accesso in lettura e scrittura sul database o sul percorso di archiviazione specificato.
  • Percorso: il database o il percorso di archiviazione, rappresentato come percorso URI.
  • Regola: l'istruzione allow , che include una condizione che consente una richiesta se restituisce true.

Ciascuno di questi concetti è descritto più dettagliatamente di seguito.

Database in tempo reale

In Realtime Database, le regole di sicurezza di Firebase sono costituite da espressioni simili a JavaScript contenute in un documento JSON.

Usano la seguente sintassi:

{
  "rules": {
    "<<path>>": {
    // Allow the request if the condition for each method is true.
      ".read": <<condition>>,
      ".write": <<condition>>,
      ".validate": <<condition>>
    }
  }
}

Ci sono tre elementi fondamentali nella regola:

  • Percorso: la posizione del database. Questo rispecchia la struttura JSON del tuo database.
  • Richiesta: questi sono i metodi utilizzati dalla regola per concedere l'accesso. Le regole read e write garantiscono un ampio accesso in lettura e scrittura, mentre le regole validate fungono da verifica secondaria per concedere l'accesso in base ai dati in entrata o esistenti.
  • Condizione: la condizione che consente una richiesta se restituisce true.

Costrutti di regole

CloudFirestore

Gli elementi di base di una regola in Cloud Firestore e Cloud Storage sono i seguenti:

  • La dichiarazione service : dichiara il prodotto Firebase a cui si applicano le regole.
  • Il blocco match : definisce un percorso nel database o nel bucket di archiviazione a cui si applicano le regole.
  • L'istruzione allow : Fornisce le condizioni per la concessione dell'accesso, differenziate in base ai metodi. I metodi supportati includono: get , list , create , update , delete e i metodi pratici read e write .
  • Dichiarazioni function facoltative: offrono la possibilità di combinare e avvolgere le condizioni per l'utilizzo in più regole.

Il service contiene uno o più blocchi match con istruzioni allow che forniscono condizioni che garantiscono l'accesso alle richieste. Le variabili request e resource sono disponibili per l'uso nelle condizioni delle regole. Il linguaggio Firebase Security Rules supporta anche le dichiarazioni function .

Versione della sintassi

L'istruzione di syntax indica la versione del linguaggio Firebase Rules utilizzato per scrivere l'origine. L'ultima versione del linguaggio è v2 .

rules_version = '2';
service cloud.firestore {
...
}

Se non viene fornita alcuna istruzione rules_version , le tue regole verranno valutate utilizzando il motore v1 .

Servizio

La dichiarazione service definisce a quale prodotto o servizio Firebase si applicano le tue regole. Puoi includere solo una dichiarazione service per file di origine.

CloudFirestore

service cloud.firestore {
 // Your 'match' blocks with their corresponding 'allow' statements and
 // optional 'function' declarations are contained here
}

Archiviazione cloud

service firebase.storage {
  // Your 'match' blocks with their corresponding 'allow' statements and
  // optional 'function' declarations are contained here
}

Se stai definendo le regole sia per Cloud Firestore che per Cloud Storage utilizzando l'interfaccia a riga di comando di Firebase, dovrai conservarle in file separati.

Incontro

Un blocco match dichiara un modello path che viene confrontato con il percorso per l'operazione richiesta ( request.path in entrata). Il corpo della match deve avere uno o più blocchi match nidificati, istruzioni allow o dichiarazioni function . Il percorso nei blocchi match nidificati è relativo al percorso nel blocco match padre.

Il modello path è un nome simile a una directory che può includere variabili o caratteri jolly. Il modello path consente corrispondenze di segmenti a percorso singolo e segmenti a percorso multiplo. Tutte le variabili associate a un path sono visibili all'interno dell'ambito match o di qualsiasi ambito annidato in cui è dichiarato il path .

Le corrispondenze rispetto a un modello path possono essere parziali o complete:

  • Corrispondenze parziali: il modello path è una corrispondenza di prefisso di request.path .
  • Corrispondenze complete: il modello path corrisponde all'intero request.path .

Quando viene effettuata una corrispondenza completa , vengono valutate le regole all'interno del blocco. Quando viene effettuata una corrispondenza parziale , le regole match nidificate vengono verificate per verificare se un path nidificato completerà la corrispondenza.

Le regole in ogni match completa vengono valutate per determinare se consentire la richiesta. Se una regola corrispondente concede l'accesso, la richiesta è consentita. Se nessuna regola corrispondente concede l'accesso, la richiesta viene rifiutata.

// Given request.path == /example/hello/nested/path the following
// declarations indicate whether they are a partial or complete match and
// the value of any variables visible within the scope.
service firebase.storage {
  // Partial match.
  match /example/{singleSegment} {   // `singleSegment` == 'hello'
    allow write;                     // Write rule not evaluated.
    // Complete match.
    match /nested/path {             // `singleSegment` visible in scope.
      allow read;                    // Read rule is evaluated.
    }
  }
  // Complete match.
  match /example/{multiSegment=**} { // `multiSegment` == /hello/nested/path
    allow read;                      // Read rule is evaluated.
  }
}

Come mostra l'esempio precedente, le dichiarazioni path supportano le seguenti variabili:

  • Carattere jolly a segmento singolo: una variabile jolly viene dichiarata in un percorso racchiudendo una variabile tra parentesi graffe: {variable} . Questa variabile è accessibile all'interno dell'istruzione match come string .
  • Carattere jolly ricorsivo: il carattere jolly ricorsivo o multisegmento corrisponde a più segmenti di percorso in corrispondenza o al di sotto di un percorso. Questo carattere jolly corrisponde a tutti i percorsi al di sotto della posizione in cui lo hai impostato. Puoi dichiararlo aggiungendo la stringa =** alla fine della tua variabile di segmento: {variable=**} . Questa variabile è accessibile all'interno dell'istruzione match come oggetto path .

Permettere

Il blocco match contiene una o più istruzioni allow . Queste sono le tue regole effettive. Puoi applicare le regole allow a uno o più metodi. Le condizioni in un'istruzione allow devono essere valutate come true affinché Cloud Firestore o Cloud Storage acconsentano a qualsiasi richiesta in arrivo. Puoi anche scrivere istruzioni allow senza condizioni, ad esempio allow read . Se l'istruzione allow non include una condizione, tuttavia, consente sempre la richiesta per quel metodo.

Se una delle regole allow per il metodo è soddisfatta, la richiesta è consentita. Inoltre, se una regola più ampia concede l'accesso, le regole concedono l'accesso e ignorano eventuali regole più granulari che potrebbero limitare l'accesso.

Si consideri l'esempio seguente, in cui qualsiasi utente può leggere o eliminare i propri file. Una regola più granulare consente le scritture solo se l'utente che richiede la scrittura possiede il file e il file è un PNG. Un utente può eliminare qualsiasi file nel sottopercorso, anche se non sono PNG, poiché la regola precedente lo consente.

service firebase.storage {
  // Allow the requestor to read or delete any resource on a path under the
  // user directory.
  match /users/{userId}/{anyUserFile=**} {
    allow read, delete: if request.auth != null && request.auth.uid == userId;
  }

  // Allow the requestor to create or update their own images.
  // When 'request.method' == 'delete' this rule and the one matching
  // any path under the user directory would both match and the `delete`
  // would be permitted.

  match /users/{userId}/images/{imageId} {
    // Whether to permit the request depends on the logical OR of all
    // matched rules. This means that even if this rule did not explicitly
    // allow the 'delete' the earlier rule would have.
    allow write: if request.auth != null && request.auth.uid == userId && imageId.matches('*.png');
  }
}

Metodo

Ogni istruzione allow include un metodo che concede l'accesso per le richieste in entrata dello stesso metodo.

Metodo Tipo di richiesta
Metodi di convenienza
read Qualsiasi tipo di richiesta di lettura
write Qualsiasi tipo di richiesta di scrittura
Metodi standard
get Richieste di lettura per singoli documenti o fascicoli
list Leggi le richieste di query e raccolte
create Scrivi nuovi documenti o file
update Scrivi su documenti di database esistenti o aggiorna i metadati dei file
delete Elimina dati

Non è possibile sovrapporre metodi di lettura nello stesso blocco match o metodi di scrittura in conflitto nella stessa dichiarazione path .

Ad esempio, le seguenti regole fallirebbero:

service bad.example {
  match /rules/with/overlapping/methods {
    // This rule allows reads to all authenticated users
    allow read: if request.auth != null;

    match another/subpath {
      // This secondary, more specific read rule causes an error
      allow get: if request.auth != null && request.auth.uid == "me";
      // Overlapping write methods in the same path cause an error as well
      allow write: if request.auth != null;
      allow create: if request.auth != null && request.auth.uid == "me";
    }
  }
}

Funzione

Man mano che le tue regole di sicurezza diventano più complesse, potresti voler racchiudere insiemi di condizioni in funzioni che puoi riutilizzare nel tuo set di regole. Le regole di sicurezza supportano funzioni personalizzate. La sintassi per le funzioni personalizzate è un po' come JavaScript, ma le funzioni delle regole di sicurezza sono scritte in un linguaggio specifico del dominio che presenta alcune limitazioni importanti:

  • Le funzioni possono contenere solo una singola istruzione return . Non possono contenere alcuna logica aggiuntiva. Ad esempio, non possono eseguire loop o chiamare servizi esterni.
  • Le funzioni possono accedere automaticamente a funzioni e variabili dall'ambito in cui sono definite. Ad esempio, una funzione definita all'interno dell'ambito del service cloud.firestore ha accesso alla variabile resource e alle funzioni integrate come get() ed exists() .
  • Le funzioni possono chiamare altre funzioni ma non possono ricorrere. La profondità totale dello stack di chiamate è limitata a 20.
  • Nella versione delle regole v2 , le funzioni possono definire variabili utilizzando la parola chiave let . Le funzioni possono avere fino a 10 associazioni let, ma devono terminare con un'istruzione return.

Una funzione è definita con la parola chiave function e accetta zero o più argomenti. Ad esempio, potresti voler combinare i due tipi di condizioni utilizzate negli esempi precedenti in un'unica funzione:

service cloud.firestore {
  match /databases/{database}/documents {
    // True if the user is signed in or the requested data is 'public'
    function signedInOrPublic() {
      return request.auth.uid != null || resource.data.visibility == 'public';
    }

    match /cities/{city} {
      allow read, write: if signedInOrPublic();
    }

    match /users/{user} {
      allow read, write: if signedInOrPublic();
    }
  }
}

Di seguito è riportato un esempio che mostra gli argomenti della funzione e le assegnazioni let. Le dichiarazioni di assegnazione Let devono essere separate da punti e virgola.

function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
  return isAuthor || isAdmin;
}

Si noti come l'assegnazione isAdmin imponga una ricerca della raccolta admins. Per una valutazione pigra senza richiedere ricerche non necessarie, sfrutta la natura di cortocircuito di && (AND) e || (OR) confronti per chiamare una seconda funzione solo se isAuthor viene mostrato come vero (per confronti && ) o falso (per confronti || ).

function isAdmin(userId) {
  return exists(/databases/$(database)/documents/admins/$(userId));
}
function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  // `||` is short-circuiting; isAdmin called only if isAuthor == false.
  return isAuthor || isAdmin(userId);
}

L'utilizzo delle funzioni nelle regole di sicurezza le rende più gestibili con l'aumentare della complessità delle regole.

Archiviazione cloud

Gli elementi di base di una regola in Cloud Firestore e Cloud Storage sono i seguenti:

  • La dichiarazione service : dichiara il prodotto Firebase a cui si applicano le regole.
  • Il blocco match : definisce un percorso nel database o nel bucket di archiviazione a cui si applicano le regole.
  • L'istruzione allow : Fornisce le condizioni per la concessione dell'accesso, differenziate in base ai metodi. I metodi supportati includono: get , list , create , update , delete e i metodi pratici read e write .
  • Dichiarazioni function facoltative: offrono la possibilità di combinare e avvolgere le condizioni per l'utilizzo in più regole.

Il service contiene uno o più blocchi match con istruzioni allow che forniscono condizioni che garantiscono l'accesso alle richieste. Le variabili request e resource sono disponibili per l'uso nelle condizioni delle regole. Il linguaggio Firebase Security Rules supporta anche le dichiarazioni function .

Versione della sintassi

L'istruzione di syntax indica la versione del linguaggio Firebase Rules utilizzato per scrivere l'origine. L'ultima versione del linguaggio è v2 .

rules_version = '2';
service cloud.firestore {
...
}

Se non viene fornita alcuna istruzione rules_version , le tue regole verranno valutate utilizzando il motore v1 .

Servizio

La dichiarazione service definisce a quale prodotto o servizio Firebase si applicano le tue regole. Puoi includere solo una dichiarazione service per file di origine.

CloudFirestore

service cloud.firestore {
 // Your 'match' blocks with their corresponding 'allow' statements and
 // optional 'function' declarations are contained here
}

Archiviazione cloud

service firebase.storage {
  // Your 'match' blocks with their corresponding 'allow' statements and
  // optional 'function' declarations are contained here
}

Se stai definendo le regole sia per Cloud Firestore che per Cloud Storage utilizzando l'interfaccia a riga di comando di Firebase, dovrai conservarle in file separati.

Incontro

Un blocco match dichiara un modello path che viene confrontato con il percorso per l'operazione richiesta ( request.path in entrata). Il corpo della match deve avere uno o più blocchi match nidificati, istruzioni allow o dichiarazioni function . Il percorso nei blocchi match nidificati è relativo al percorso nel blocco match padre.

Il modello path è un nome simile a una directory che può includere variabili o caratteri jolly. Il modello path consente corrispondenze di segmenti a percorso singolo e segmenti a percorso multiplo. Tutte le variabili associate a un path sono visibili all'interno dell'ambito match o di qualsiasi ambito annidato in cui è dichiarato il path .

Le corrispondenze rispetto a un modello path possono essere parziali o complete:

  • Corrispondenze parziali: il modello path è una corrispondenza di prefisso di request.path .
  • Corrispondenze complete: il modello path corrisponde all'intero request.path .

Quando viene effettuata una corrispondenza completa , vengono valutate le regole all'interno del blocco. Quando viene effettuata una corrispondenza parziale , le regole match nidificate vengono verificate per verificare se un path nidificato completerà la corrispondenza.

Le regole in ogni match completa vengono valutate per determinare se consentire la richiesta. Se una regola corrispondente concede l'accesso, la richiesta è consentita. Se nessuna regola corrispondente concede l'accesso, la richiesta viene rifiutata.

// Given request.path == /example/hello/nested/path the following
// declarations indicate whether they are a partial or complete match and
// the value of any variables visible within the scope.
service firebase.storage {
  // Partial match.
  match /example/{singleSegment} {   // `singleSegment` == 'hello'
    allow write;                     // Write rule not evaluated.
    // Complete match.
    match /nested/path {             // `singleSegment` visible in scope.
      allow read;                    // Read rule is evaluated.
    }
  }
  // Complete match.
  match /example/{multiSegment=**} { // `multiSegment` == /hello/nested/path
    allow read;                      // Read rule is evaluated.
  }
}

Come mostra l'esempio precedente, le dichiarazioni path supportano le seguenti variabili:

  • Carattere jolly a segmento singolo: una variabile jolly viene dichiarata in un percorso racchiudendo una variabile tra parentesi graffe: {variable} . Questa variabile è accessibile all'interno dell'istruzione match come string .
  • Carattere jolly ricorsivo: il carattere jolly ricorsivo o multisegmento corrisponde a più segmenti di percorso in corrispondenza o al di sotto di un percorso. Questo carattere jolly corrisponde a tutti i percorsi al di sotto della posizione in cui lo hai impostato. Puoi dichiararlo aggiungendo la stringa =** alla fine della tua variabile di segmento: {variable=**} . Questa variabile è accessibile all'interno dell'istruzione match come oggetto path .

Permettere

Il blocco match contiene una o più istruzioni allow . Queste sono le tue regole effettive. Puoi applicare le regole allow a uno o più metodi. Le condizioni in un'istruzione allow devono essere valutate come true affinché Cloud Firestore o Cloud Storage acconsentano a qualsiasi richiesta in arrivo. Puoi anche scrivere istruzioni allow senza condizioni, ad esempio allow read . Se l'istruzione allow non include una condizione, tuttavia, consente sempre la richiesta per quel metodo.

Se una delle regole allow per il metodo è soddisfatta, la richiesta è consentita. Inoltre, se una regola più ampia concede l'accesso, le regole concedono l'accesso e ignorano eventuali regole più granulari che potrebbero limitare l'accesso.

Si consideri l'esempio seguente, in cui qualsiasi utente può leggere o eliminare i propri file. Una regola più granulare consente le scritture solo se l'utente che richiede la scrittura possiede il file e il file è un PNG. Un utente può eliminare qualsiasi file nel sottopercorso, anche se non sono PNG, poiché la regola precedente lo consente.

service firebase.storage {
  // Allow the requestor to read or delete any resource on a path under the
  // user directory.
  match /users/{userId}/{anyUserFile=**} {
    allow read, delete: if request.auth != null && request.auth.uid == userId;
  }

  // Allow the requestor to create or update their own images.
  // When 'request.method' == 'delete' this rule and the one matching
  // any path under the user directory would both match and the `delete`
  // would be permitted.

  match /users/{userId}/images/{imageId} {
    // Whether to permit the request depends on the logical OR of all
    // matched rules. This means that even if this rule did not explicitly
    // allow the 'delete' the earlier rule would have.
    allow write: if request.auth != null && request.auth.uid == userId && imageId.matches('*.png');
  }
}

Metodo

Ogni istruzione allow include un metodo che concede l'accesso per le richieste in entrata dello stesso metodo.

Metodo Tipo di richiesta
Metodi di convenienza
read Qualsiasi tipo di richiesta di lettura
write Qualsiasi tipo di richiesta di scrittura
Metodi standard
get Richieste di lettura per singoli documenti o fascicoli
list Leggi le richieste di query e raccolte
create Scrivi nuovi documenti o file
update Scrivi su documenti di database esistenti o aggiorna i metadati dei file
delete Elimina dati

Non è possibile sovrapporre metodi di lettura nello stesso blocco match o metodi di scrittura in conflitto nella stessa dichiarazione path .

Ad esempio, le seguenti regole fallirebbero:

service bad.example {
  match /rules/with/overlapping/methods {
    // This rule allows reads to all authenticated users
    allow read: if request.auth != null;

    match another/subpath {
      // This secondary, more specific read rule causes an error
      allow get: if request.auth != null && request.auth.uid == "me";
      // Overlapping write methods in the same path cause an error as well
      allow write: if request.auth != null;
      allow create: if request.auth != null && request.auth.uid == "me";
    }
  }
}

Funzione

Man mano che le tue regole di sicurezza diventano più complesse, potresti voler racchiudere insiemi di condizioni in funzioni che puoi riutilizzare nel tuo set di regole. Le regole di sicurezza supportano funzioni personalizzate. La sintassi per le funzioni personalizzate è un po' come JavaScript, ma le funzioni delle regole di sicurezza sono scritte in un linguaggio specifico del dominio che presenta alcune limitazioni importanti:

  • Le funzioni possono contenere solo una singola istruzione return . Non possono contenere alcuna logica aggiuntiva. Ad esempio, non possono eseguire loop o chiamare servizi esterni.
  • Le funzioni possono accedere automaticamente a funzioni e variabili dall'ambito in cui sono definite. Ad esempio, una funzione definita all'interno dell'ambito del service cloud.firestore ha accesso alla variabile resource e alle funzioni integrate come get() ed exists() .
  • Le funzioni possono chiamare altre funzioni ma non possono ricorrere. La profondità totale dello stack di chiamate è limitata a 20.
  • Nella versione delle regole v2 , le funzioni possono definire variabili utilizzando la parola chiave let . Le funzioni possono avere fino a 10 associazioni let, ma devono terminare con un'istruzione return.

Una funzione è definita con la parola chiave function e accetta zero o più argomenti. Ad esempio, potresti voler combinare i due tipi di condizioni utilizzate negli esempi precedenti in un'unica funzione:

service cloud.firestore {
  match /databases/{database}/documents {
    // True if the user is signed in or the requested data is 'public'
    function signedInOrPublic() {
      return request.auth.uid != null || resource.data.visibility == 'public';
    }

    match /cities/{city} {
      allow read, write: if signedInOrPublic();
    }

    match /users/{user} {
      allow read, write: if signedInOrPublic();
    }
  }
}

Di seguito è riportato un esempio che mostra gli argomenti della funzione e le assegnazioni let. Le dichiarazioni di assegnazione Let devono essere separate da punti e virgola.

function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
  return isAuthor || isAdmin;
}

Si noti come l'assegnazione isAdmin imponga una ricerca della raccolta admins. Per una valutazione pigra senza richiedere ricerche non necessarie, sfrutta la natura di cortocircuito di && (AND) e || (OR) confronti per chiamare una seconda funzione solo se isAuthor viene mostrato come vero (per confronti && ) o falso (per confronti || ).

function isAdmin(userId) {
  return exists(/databases/$(database)/documents/admins/$(userId));
}
function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  // `||` is short-circuiting; isAdmin called only if isAuthor == false.
  return isAuthor || isAdmin(userId);
}

L'utilizzo delle funzioni nelle regole di sicurezza le rende più gestibili con l'aumentare della complessità delle regole.

Database in tempo reale

Come indicato in precedenza, le regole del database in tempo reale includono tre elementi di base: la posizione del database come mirror della struttura JSON del database, il tipo di richiesta e la condizione che concede l'accesso.

Posizione della banca dati

La struttura delle tue regole dovrebbe seguire la struttura dei dati che hai memorizzato nel tuo database. Ad esempio, in un'app di chat con un elenco di messaggi, potresti avere dati simili a questi:

  {
    "messages": {
      "message0": {
        "content": "Hello",
        "timestamp": 1405704370369
      },
      "message1": {
        "content": "Goodbye",
        "timestamp": 1405704395231
      },
      ...
    }
  }

Le tue regole dovrebbero rispecchiare quella struttura. Per esempio:

  {
    "rules": {
      "messages": {
        "$message": {
          // only messages from the last ten minutes can be read
          ".read": "data.child('timestamp').val() > (now - 600000)",

          // new messages must have a string content and a number timestamp
          ".validate": "newData.hasChildren(['content', 'timestamp']) &&
                        newData.child('content').isString() &&
                        newData.child('timestamp').isNumber()"
        }
      }
    }
  }

Come mostra l'esempio sopra, le regole del database in tempo reale supportano una variabile $location per abbinare i segmenti del percorso. Usa il prefisso $ davanti al tuo segmento di percorso per far corrispondere la tua regola a qualsiasi nodo figlio lungo il percorso.

  {
    "rules": {
      "rooms": {
        // This rule applies to any child of /rooms/, the key for each room id
        // is stored inside $room_id variable for reference
        "$room_id": {
          "topic": {
            // The room's topic can be changed if the room id has "public" in it
            ".write": "$room_id.contains('public')"
          }
        }
      }
    }
  }

È inoltre possibile utilizzare la $variable in parallelo con nomi di percorso costanti.

  {
    "rules": {
      "widget": {
        // a widget can have a title or color attribute
        "title": { ".validate": true },
        "color": { ".validate": true },

        // but no other child paths are allowed
        // in this case, $other means any key excluding "title" and "color"
        "$other": { ".validate": false }
      }
    }
  }

Metodo

In Realtime Database esistono tre tipi di regole. Due di questi tipi di regole, read e write , si applicano al metodo di una richiesta in entrata. Il tipo di regola validate applica le strutture dei dati e convalida il formato e il contenuto dei dati. Le regole eseguono regole .validate dopo aver verificato che una regola .write conceda l'accesso.

Tipi di regole
.Leggere Descrive se e quando i dati possono essere letti dagli utenti.
.scrivere Descrive se e quando i dati possono essere scritti.
.convalidare Definisce l'aspetto di un valore formattato correttamente, se dispone di attributi figlio e il tipo di dati.

Per impostazione predefinita, se non esiste una regola che lo consenta, l'accesso a un percorso è negato.

Condizioni di costruzione

CloudFirestore

Una condizione è un'espressione booleana che determina se una particolare operazione deve essere consentita o negata. Le variabili request e resource forniscono il contesto per tali condizioni.

La variabile request

La variabile request include i seguenti campi e le informazioni corrispondenti:

request.auth

Un JSON Web Token (JWT) che contiene le credenziali di autenticazione da Firebase Authentication. Il token auth contiene una serie di attestazioni standard ed eventuali attestazioni personalizzate create tramite l'autenticazione Firebase. Scopri di più sulle regole di sicurezza e sull'autenticazione di Firebase .

request.method

request.method può essere uno qualsiasi dei metodi standard o un metodo personalizzato. I metodi di convenienza read e write esistono anche per semplificare le regole di scrittura che si applicano rispettivamente a tutti i metodi standard di sola lettura oa tutti i metodi di sola scrittura.

request.params

I request.params includono tutti i dati non specificamente correlati alla request.resource che potrebbero essere utili per la valutazione. In pratica, questa mappa dovrebbe essere vuota per tutti i metodi standard e dovrebbe contenere dati non di risorse per metodi personalizzati. I servizi devono fare attenzione a non rinominare o modificare il tipo di nessuna delle chiavi e dei valori presentati come parametri.

request.path

request.path è il percorso per la resource di destinazione. Il percorso è relativo al servizio. I segmenti di percorso contenenti caratteri sicuri non URL come / sono codificati con URL.

La variabile resource

La resource è il valore corrente all'interno del servizio rappresentato come una mappa di coppie chiave-valore. Il riferimento resource all'interno di una condizione comporterà al massimo una lettura del valore dal servizio. Questa ricerca verrà conteggiata rispetto a qualsiasi quota correlata al servizio per la risorsa. Per le richieste get , la resource verrà conteggiata solo per la quota in caso di rifiuto.

Operatori e precedenza degli operatori

Utilizza la tabella seguente come riferimento per gli operatori e la relativa precedenza nelle regole per Cloud Firestore e Cloud Storage.

Date le espressioni arbitrarie a e b , un campo f e un indice i .

Operatore Descrizione Associatività
a[i] a() af Indice, chiamata, accesso al campo da sinistra a destra
!a -a Negazione unaria da destra a sinistra
a/ba%ba*b Operatori moltiplicativi da sinistra a destra
a+b ab Operatori additivi da sinistra a destra
a>ba>=ba Operatori relazionali da sinistra a destra
a in b Esistenza in lista o mappa da sinistra a destra
a is type Confronto di tipi, dove type può essere bool, int, float, number, string, list, map, timestamp, duration, path o latlng da sinistra a destra
a==ba!=b Operatori di confronto da sinistra a destra
a && b AND condizionale da sinistra a destra
a || b OR condizionale da sinistra a destra
a ? true_value : false_value Espressione ternaria da sinistra a destra

Archiviazione cloud

Una condizione è un'espressione booleana che determina se una particolare operazione deve essere consentita o negata. Le variabili request e resource forniscono il contesto per tali condizioni.

La variabile request

La variabile request include i seguenti campi e le informazioni corrispondenti:

request.auth

Un JSON Web Token (JWT) che contiene le credenziali di autenticazione da Firebase Authentication. Il token auth contiene una serie di attestazioni standard ed eventuali attestazioni personalizzate create tramite l'autenticazione Firebase. Scopri di più sulle regole di sicurezza e sull'autenticazione di Firebase .

request.method

request.method può essere uno qualsiasi dei metodi standard o un metodo personalizzato. I metodi di convenienza read e write esistono anche per semplificare le regole di scrittura che si applicano rispettivamente a tutti i metodi standard di sola lettura oa tutti i metodi di sola scrittura.

request.params

I request.params includono tutti i dati non specificamente correlati alla request.resource che potrebbero essere utili per la valutazione. In pratica, questa mappa dovrebbe essere vuota per tutti i metodi standard e dovrebbe contenere dati non di risorse per metodi personalizzati. I servizi devono fare attenzione a non rinominare o modificare il tipo di nessuna delle chiavi e dei valori presentati come parametri.

request.path

request.path è il percorso per la resource di destinazione. Il percorso è relativo al servizio. I segmenti di percorso contenenti caratteri sicuri non URL come / sono codificati con URL.

La variabile resource

La resource è il valore corrente all'interno del servizio rappresentato come una mappa di coppie chiave-valore. Il riferimento resource all'interno di una condizione comporterà al massimo una lettura del valore dal servizio. Questa ricerca verrà conteggiata rispetto a qualsiasi quota correlata al servizio per la risorsa. Per le richieste get , la resource verrà conteggiata solo per la quota in caso di rifiuto.

Operatori e precedenza degli operatori

Utilizza la tabella seguente come riferimento per gli operatori e la relativa precedenza nelle regole per Cloud Firestore e Cloud Storage.

Date le espressioni arbitrarie a e b , un campo f e un indice i .

Operatore Descrizione Associatività
a[i] a() af Indice, chiamata, accesso al campo da sinistra a destra
!a -a Negazione unaria da destra a sinistra
a/ba%ba*b Operatori moltiplicativi da sinistra a destra
a+b ab Operatori additivi da sinistra a destra
a>ba>=ba Operatori relazionali da sinistra a destra
a in b Esistenza in lista o mappa da sinistra a destra
a is type Confronto di tipi, dove type può essere bool, int, float, number, string, list, map, timestamp, duration, path o latlng da sinistra a destra
a==ba!=b Operatori di confronto da sinistra a destra
a && b AND condizionale da sinistra a destra
a || b OR condizionale da sinistra a destra
a ? true_value : false_value Espressione ternaria da sinistra a destra

Database in tempo reale

Una condizione è un'espressione booleana che determina se una particolare operazione deve essere consentita o negata. È possibile definire tali condizioni nelle regole del database in tempo reale nei seguenti modi.

Variabili predefinite

Esistono numerose utili variabili predefinite a cui è possibile accedere all'interno di una definizione di regola. Ecco un breve riassunto di ciascuno:

Variabili predefinite
Ora L'ora corrente in millisecondi dall'epoca di Linux. Funziona particolarmente bene per la convalida dei timestamp creati con firebase.database.ServerValue.TIMESTAMP dell'SDK.
radice Un RuleDataSnapshot che rappresenta il percorso root nel database Firebase come esisteva prima dell'operazione tentata.
newDati Oggetto RuleDataSnapshot che rappresenta i dati così come esisterebbero dopo l'operazione tentata. Include i nuovi dati scritti ei dati esistenti.
dati Oggetto RuleDataSnapshot che rappresenta i dati esistenti prima dell'operazione tentata.
variabili $ Un percorso con caratteri jolly utilizzato per rappresentare ID e chiavi figlio dinamiche.
aut Rappresenta il payload del token di un utente autenticato.

Queste variabili possono essere utilizzate ovunque nelle tue regole. Ad esempio, le regole di sicurezza seguenti assicurano che i dati scritti nel nodo /foo/ debbano essere una stringa di meno di 100 caratteri:

{
  "rules": {
    "foo": {
      // /foo is readable by the world
      ".read": true,

      // /foo is writable by the world
      ".write": true,

      // data written to /foo must be a string less than 100 characters
      ".validate": "newData.isString() && newData.val().length < 100"
    }
  }
}

Regole basate sui dati

Qualsiasi dato nel tuo database può essere utilizzato nelle tue regole. Usando le variabili predefinite root , data e newData , puoi accedere a qualsiasi percorso come esisterebbe prima o dopo un evento di scrittura.

Considera questo esempio, che consente operazioni di scrittura fintanto che il valore del nodo /allow_writes/ è true , il nodo padre non ha un flag readOnly impostato e c'è un figlio chiamato foo nei dati appena scritti:

".write": "root.child('allow_writes').val() === true &&
          !data.parent().child('readOnly').exists() &&
          newData.child('foo').exists()"

Regole basate su query

Sebbene non sia possibile utilizzare le regole come filtri, è possibile limitare l'accesso a sottoinsiemi di dati utilizzando i parametri di query nelle regole. Usa query. espressioni nelle regole per concedere l'accesso in lettura o scrittura in base ai parametri di query.

Ad esempio, la seguente regola basata su query utilizza regole di sicurezza basate sull'utente e regole basate su query per limitare l'accesso ai dati nella raccolta baskets solo ai carrelli acquisti di proprietà dell'utente attivo:

"baskets": {
  ".read": "auth.uid !== null &&
            query.orderByChild === 'owner' &&
            query.equalTo === auth.uid" // restrict basket access to owner of basket
}

La seguente query, che include i parametri della query nella regola, avrà esito positivo:

db.ref("baskets").orderByChild("owner")
                 .equalTo(auth.currentUser.uid)
                 .on("value", cb)                 // Would succeed

Tuttavia, le query che non includono i parametri nella regola fallirebbero con un errore PermissionDenied :

db.ref("baskets").on("value", cb)                 // Would fail with PermissionDenied

È inoltre possibile utilizzare regole basate su query per limitare la quantità di dati scaricati da un client tramite operazioni di lettura.

Ad esempio, la seguente regola limita l'accesso in lettura solo ai primi 1000 risultati di una query, in ordine di priorità:

messages: {
  ".read": "query.orderByKey &&
            query.limitToFirst <= 1000"
}

// Example queries:

db.ref("messages").on("value", cb)                // Would fail with PermissionDenied

db.ref("messages").limitToFirst(1000)
                  .on("value", cb)                // Would succeed (default order by key)

La seguente query. le espressioni sono disponibili nelle regole di sicurezza del database in tempo reale.

Espressioni di regole basate su query
Espressione Tipo Descrizione
query.orderByKey
query.orderByPriority
query.orderByValue
booleano True per le query ordinate per chiave, priorità o valore. Falso altrimenti.
query.orderByChild corda
nullo
Utilizzare una stringa per rappresentare il percorso relativo a un nodo figlio. Ad esempio, query.orderByChild === "address/zip" . Se la query non è ordinata da un nodo figlio, questo valore è null.
query.startAt
query.endAt
query.equalTo
corda
numero
booleano
nullo
Recupera i limiti della query in esecuzione o restituisce null se non è impostato alcun limite.
query.limitToFirst
query.limitToLast
numero
nullo
Recupera il limite sulla query in esecuzione o restituisce null se non è stato impostato alcun limite.

Operatori

Le regole del database in tempo reale supportano una serie di operatori che è possibile utilizzare per combinare le variabili nell'istruzione condizionale. Vedere l'elenco completo degli operatori nella documentazione di riferimento .

Creazione di condizioni

Le tue condizioni effettive varieranno in base all'accesso che vuoi concedere. Le regole offrono intenzionalmente un enorme grado di flessibilità, quindi le regole della tua app possono essere semplici o complesse in base alle tue esigenze.

Per indicazioni sulla creazione di regole semplici e pronte per la produzione, consulta Regole di sicurezza di base .