Linguaggio delle regole di sicurezza

Le regole di sicurezza 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 su Common Expression Language (CEL) , che si basa su CEL con match e allow istruzioni che supportano l'accesso condizionato.

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

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

Struttura basilare

Cloud Firestore

Le regole di sicurezza 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 invocati nell'istruzione allow . Questi sono metodi che stai permettendo di eseguire. I metodi standard sono: get , list , create , update e delete . I metodi pratici di read e write consentono un ampio accesso in lettura e scrittura al database o al percorso di archiviazione specificato.
  • Percorso: il database o il percorso di archiviazione, rappresentato come un percorso URI.
  • Regola: l'istruzione allow , che include una condizione che consente una richiesta se risulta true.

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

Archiviazione su cloud

Le regole di sicurezza 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 invocati nell'istruzione allow . Questi sono metodi che stai permettendo di eseguire. I metodi standard sono: get , list , create , update e delete . I metodi pratici di read e write consentono un ampio accesso in lettura e scrittura al database o al percorso di archiviazione specificato.
  • Percorso: il database o il percorso di archiviazione, rappresentato come un percorso URI.
  • Regola: l'istruzione allow , che include una condizione che consente una richiesta se risulta true.

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

Database in tempo reale

In Realtime Database, le regole di sicurezza 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 di read e write garantiscono un ampio accesso in lettura e scrittura, mentre le regole di 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

Cloud Firestore

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 di 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 di function opzionali: offrono la possibilità di combinare e racchiudere le condizioni per l'uso su più regole.

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

Versione sintattica

L'istruzione di syntax indica la versione del linguaggio Firebase Rules utilizzato per scrivere il codice sorgente. L'ultima versione della lingua è 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 di service per file di origine.

Cloud Firestore

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

Archiviazione su 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 mantenerle in file separati.

Incontro

Un blocco di match dichiara un modello di 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 di match nidificati, istruzioni di allow o dichiarazioni di function . Il percorso nei blocchi di match nidificati è relativo al percorso nel blocco di match padre.

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

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

  • Corrispondenze parziali: il modello di path è una corrispondenza di prefisso di request.path .
  • Corrispondenze complete: il modello di 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 di 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 di corrispondenza concede l'accesso, la richiesta è consentita. Se nessuna regola di corrispondenza concede l'accesso, la richiesta viene negata.

// 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 sopra, le dichiarazioni di 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 multi-segmento corrisponde a più segmenti di percorso in corrispondenza o al di sotto di un percorso. Questo carattere jolly corrisponde a tutti i percorsi sotto la posizione in cui lo hai impostato. Puoi dichiararlo aggiungendo la stringa =** alla fine della variabile del segmento: {variable=**} . Questa variabile è accessibile all'interno dell'istruzione match come oggetto path .

Permettere

Il blocco di match contiene una o più istruzioni di allow . Queste sono le tue regole effettive. È possibile applicare regole di allow a uno o più metodi. Le condizioni su un'istruzione di allow devono essere valutate come true affinché Cloud Firestore o Cloud Storage conceda qualsiasi richiesta in entrata. 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 qualsiasi delle regole di 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.

Considera 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, perché 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

Ciascuna 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 Leggi le richieste di singoli documenti o file
list Leggi le richieste di query e raccolte
create Scrivi nuovi documenti o file
update Scrivere in documenti di database esistenti o aggiornare i metadati dei file
delete Elimina dati

Non puoi sovrapporre metodi di lettura nello stesso blocco di match o metodi di scrittura in conflitto nella stessa dichiarazione di 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 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 importanti limitazioni:

  • 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 della resource e alle funzioni integrate come get() ed exists() .
  • Le funzioni possono chiamare altre funzioni ma non possono essere ricorrenti. La profondità totale dello stack di chiamate è limitata a 20.
  • Nella versione delle regole v2 , le funzioni possono definire variabili usando la parola chiave let . Le funzioni possono avere fino a 10 let binding, 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 utilizzati 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();
    }
  }
}

Ecco un esempio che mostra gli argomenti delle funzioni e le assegnazioni dei let. Le istruzioni di assegnazione devono essere separate da punto e virgola.

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

Nota come l'assegnazione isAdmin impone 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 risulta essere true (per && confronti) o false (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'uso delle funzioni nelle regole di sicurezza le rende più gestibili man mano che la complessità delle regole aumenta.

Archiviazione su 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 di 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 di function opzionali: offrono la possibilità di combinare e racchiudere le condizioni per l'uso su più regole.

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

Versione sintattica

L'istruzione di syntax indica la versione del linguaggio Firebase Rules utilizzato per scrivere il codice sorgente. L'ultima versione della lingua è 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 di service per file di origine.

Cloud Firestore

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

Archiviazione su 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 mantenerle in file separati.

Incontro

Un blocco di match dichiara un modello di 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 di match nidificati, istruzioni di allow o dichiarazioni di function . Il percorso nei blocchi di match nidificati è relativo al percorso nel blocco di match padre.

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

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

  • Corrispondenze parziali: il modello di path è una corrispondenza di prefisso di request.path .
  • Corrispondenze complete: il modello di 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 di 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 di corrispondenza concede l'accesso, la richiesta è consentita. Se nessuna regola di corrispondenza concede l'accesso, la richiesta viene negata.

// 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 sopra, le dichiarazioni di 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 multi-segmento corrisponde a più segmenti di percorso in corrispondenza o al di sotto di un percorso. Questo carattere jolly corrisponde a tutti i percorsi sotto la posizione in cui lo hai impostato. Puoi dichiararlo aggiungendo la stringa =** alla fine della variabile del segmento: {variable=**} . Questa variabile è accessibile all'interno dell'istruzione match come oggetto path .

Permettere

Il blocco di match contiene una o più istruzioni di allow . Queste sono le tue regole effettive. È possibile applicare regole di allow a uno o più metodi. Le condizioni su un'istruzione di allow devono essere valutate come true affinché Cloud Firestore o Cloud Storage conceda qualsiasi richiesta in entrata. 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 qualsiasi delle regole di 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.

Considera 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, perché 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

Ciascuna 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 Leggi le richieste di singoli documenti o file
list Leggi le richieste di query e raccolte
create Scrivi nuovi documenti o file
update Scrivere in documenti di database esistenti o aggiornare i metadati dei file
delete Elimina dati

Non puoi sovrapporre metodi di lettura nello stesso blocco di match o metodi di scrittura in conflitto nella stessa dichiarazione di 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 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 importanti limitazioni:

  • 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 della resource e alle funzioni integrate come get() ed exists() .
  • Le funzioni possono chiamare altre funzioni ma non possono essere ricorrenti. La profondità totale dello stack di chiamate è limitata a 20.
  • Nella versione delle regole v2 , le funzioni possono definire variabili usando la parola chiave let . Le funzioni possono avere fino a 10 let binding, 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 utilizzati 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();
    }
  }
}

Ecco un esempio che mostra gli argomenti delle funzioni e le assegnazioni dei let. Le istruzioni di assegnazione devono essere separate da punto e virgola.

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

Nota come l'assegnazione isAdmin impone 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 risulta essere true (per && confronti) o false (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'uso delle funzioni nelle regole di sicurezza le rende più gestibili man mano che la complessità delle regole aumenta.

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 specchio della struttura JSON del database, il tipo di richiesta e la condizione che concede l'accesso.

Posizione del database

La struttura delle tue regole dovrebbe seguire la struttura dei dati che hai archiviato 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 di $location per abbinare i segmenti di percorso. Usa il prefisso $ davanti al tuo segmento di percorso per abbinare 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')"
          }
        }
      }
    }
  }

Puoi anche usare la $variable in parallelo con nomi di percorsi 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, ci sono tre tipi di regole. Due di questi tipi di regole, read e write , si applicano al metodo di una richiesta in arrivo. Il tipo di regola di validate applica le strutture dei dati e convalida il formato e il contenuto dei dati. Le regole eseguono le regole .validate dopo aver verificato che una regola .write concede l'accesso.

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

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

Condizioni di costruzione

Cloud Firestore

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

La variabile request

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

request.auth

Un token Web JSON (JWT) che contiene le credenziali di autenticazione dall'autenticazione Firebase. auth token contiene una serie di attestazioni standard ed eventuali attestazioni personalizzate create tramite l'autenticazione Firebase. Ulteriori informazioni sulle regole di sicurezza e sull'autenticazione di Firebase .

request.method

Il request.method può essere uno qualsiasi dei metodi standard o un metodo personalizzato. I metodi pratici di read e write esistono anche per semplificare le regole di scrittura che si applicano rispettivamente a tutti i metodi standard di sola lettura o 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 risorsa per i 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

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

La variabile resource

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

Operatori e precedenza degli operatori

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

Date espressioni arbitrarie b , a 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 nell'elenco o nella mappa da sinistra a destra
a is type Confronto dei tipi, dove il type può essere bool, int, float, numero, stringa, elenco, mappa, timestamp, durata, percorso o latlng da sinistra a destra
a==ba!=b Operatori di confronto da sinistra a destra
a && b E condizionale da sinistra a destra
a || b condizionale OR da sinistra a destra
a ? true_value : false_value Espressione ternaria da sinistra a destra

Archiviazione su cloud

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

La variabile request

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

request.auth

Un token Web JSON (JWT) che contiene le credenziali di autenticazione dall'autenticazione Firebase. auth token contiene una serie di attestazioni standard ed eventuali attestazioni personalizzate create tramite l'autenticazione Firebase. Ulteriori informazioni sulle regole di sicurezza e sull'autenticazione di Firebase .

request.method

Il request.method può essere uno qualsiasi dei metodi standard o un metodo personalizzato. I metodi pratici di read e write esistono anche per semplificare le regole di scrittura che si applicano rispettivamente a tutti i metodi standard di sola lettura o 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 risorsa per i 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

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

La variabile resource

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

Operatori e precedenza degli operatori

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

Date espressioni arbitrarie b , a 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 nell'elenco o nella mappa da sinistra a destra
a is type Confronto dei tipi, dove il type può essere bool, int, float, numero, stringa, elenco, mappa, timestamp, durata, percorso o latlng da sinistra a destra
a==ba!=b Operatori di confronto da sinistra a destra
a && b E condizionale da sinistra a destra
a || b condizionale OR 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 in Regole database in tempo reale nei seguenti modi.

Variabili predefinite

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

Variabili predefinite
adesso 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 radice nel database Firebase così com'era prima dell'operazione tentata.
nuoviDati Un RuleDataSnapshot che rappresenta i dati come esisterebbero dopo il tentativo di operazione. Include i nuovi dati in fase di scrittura e i dati esistenti.
dati Un RuleDataSnapshot che rappresenta i dati come esistevano prima del tentativo di operazione.
$ variabili 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 inferiore a 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

Tutti i dati nel tuo database possono essere utilizzati nelle tue regole. Usando le variabili predefinite root , data e newData , puoi accedere a qualsiasi percorso come sarebbe 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 della 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 dei baskets solo ai carrelli della spesa 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 query seguente, 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 non riusciranno con un errore PermissionDenied :

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

Puoi anche utilizzare regole basate su query per limitare la quantità di dati scaricata da un client tramite operazioni di lettura.

Ad esempio, la regola seguente limita l'accesso in lettura solo ai primi 1000 risultati di una query, ordinati per 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 in Regole 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.uguale a
corda
numero
booleano
nullo
Recupera i limiti della query in esecuzione o restituisce null se non sono presenti limiti impostati.
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 variabili nell'istruzione di condizione. Vedere l'elenco completo degli operatori nella documentazione di riferimento .

Creare condizioni

Le tue condizioni effettive varieranno in base all'accesso che desideri concedere. Le regole offrono intenzionalmente un enorme grado di flessibilità, quindi le regole della tua app possono essere in definitiva tanto semplici o complesse quanto ne hai bisogno.

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