API delle regole di sicurezza del database Firebase

Regola: tipi

.Leggere

Concede a un client l'accesso in lettura a una posizione del database Firebase Realtime.

Una regola .read è un tipo di regola di sicurezza che concede a un client l'accesso in lettura a una posizione del database Firebase Realtime. Per esempio:

 ".read": "auth != null && auth.provider == 'twitter'"

Il valore di una regola .read è una stringa, che viene valutata come un sottoinsieme della sintassi dell'espressione JavaScript con alcune modifiche comportamentali per aumentare la chiarezza e la correttezza. Una regola .read che concede l'autorizzazione a leggere una posizione consentirà anche la lettura di tutti i discendenti di quella posizione, anche se i discendenti hanno le proprie regole .read che falliscono.

Una regola .read ha accesso a tutte le variabili delle regole del Firebase Realtime Database tranne newData .

.scrivere

Concede a un client l'accesso in scrittura a una posizione del database Firebase Realtime.

Una regola .write è un tipo di regola di sicurezza che concede a un client l'accesso in scrittura a una posizione del database Firebase Realtime. Per esempio:

".write": "auth != null && auth.token.isAdmin == true"

Il valore di una regola .write è una stringa, che viene valutata come un sottoinsieme della sintassi dell'espressione JavaScript con alcune modifiche comportamentali per aumentare la chiarezza e la correttezza. Una regola .write che concede l'autorizzazione a scrivere in una posizione consentirà anche la scrittura su tutti i discendenti di quella posizione, anche se i discendenti hanno le proprie regole .write che falliscono.

Una regola .write ha accesso a tutte le variabili delle regole del Firebase Realtime Database.

.convalidare

Utilizzato una volta che una regola .write ha concesso l'accesso, per garantire che i dati scritti siano conformi a uno schema specifico.

Una regola .validate viene utilizzata una volta che una regola .write ha concesso l'accesso, per garantire che i dati scritti siano conformi a uno standard specifico. Oltre a un .write che garantisce l'accesso, tutte le regole .validate pertinenti devono avere esito positivo prima che venga consentita una scrittura. Per esempio:

".validate": "newData.hasChildren(['name', 'age'])"

Il valore di una regola .validate è una stringa, che viene valutata come un sottoinsieme della sintassi dell'espressione JavaScript con alcune modifiche comportamentali per aumentare la chiarezza e la correttezza.

Una regola .validate ha accesso a tutte le variabili delle regole del Firebase Realtime Database.

.indexOn

Migliora le prestazioni delle query indicando al Firebase Realtime Database quali chiavi desideri che i tuoi dati vengano indicizzati.

La regola .indexOn indica ai server Firebase Realtime Database di indicizzare chiavi specifiche nei tuoi dati per migliorare le prestazioni delle tue query. Ad esempio, dato un database con una raccolta di dati sui dinosauri, possiamo dire a Firebase Realtime Database di ottimizzare le query, prima che vengano restituite dai server, aggiungendo questa regola:

{
  "rules": {
    "dinosaurs": {
      ".indexOn": ["height", "length"]
    }
  }
}

Puoi trovare maggiori informazioni sulla regola .indexOn facendo riferimento alla sezione della guida alla sicurezza sull'indicizzazione dei tuoi dati .

Regola: variabili

aut

Una variabile contenente il payload del token se un client è autenticato o null se il client non è autenticato.

Firebase Realtime Database ti consente di autenticarti facilmente con diversi provider integrati e genererà token di autenticazione per loro. Dopo che un utente è stato autenticato con uno dei provider integrati, la variabile auth conterrà quanto segue:

Campo Descrizione
provider Il metodo di autenticazione utilizzato (ad esempio "password", "anonimo", "facebook", "github", "google" o "twitter").
uid Un ID utente univoco, garantito per essere unico tra tutti i fornitori.
token Il contenuto del token ID autenticazione Firebase. Vedi auth.token .

Ad esempio, potremmo avere una regola come la seguente per consentire agli utenti di creare commenti purché memorizzino il proprio ID utente con il commento:

{
  "rules": {
    ".read": true,
    "$comment": {
      ".write": "!data.exists() && newData.child('user_id').val() == auth.uid"
    }
  }
}

Potremmo anche creare una regola come la seguente per consentire agli utenti di creare commenti purché abbiano effettuato l'accesso tramite Facebook:

{
  "rules": {
    ".read": true,
    "$comment": {
      ".write": "!data.exists() && auth.provider == 'facebook'"
    }
  }
}

token.auth

Una variabile contenente il contenuto del token ID autenticazione Firebase.

Il token contiene alcune o tutte le seguenti chiavi:

Campo Descrizione
email L'indirizzo email associato all'account, se presente.
email_verified true se l'utente ha verificato di avere accesso all'indirizzo email . Alcuni provider verificano automaticamente gli indirizzi email di loro proprietà.
phone_number Il numero di telefono associato all'account, se presente.
name Il nome visualizzato dell'utente, se impostato.
sub L'UID Firebase dell'utente. Questo è unico all'interno di un progetto.
firebase.identities Dizionario di tutte le identità associate all'account di questo utente. I tasti del dizionario possono essere uno dei seguenti: email , phone , google.com , facebook.com , github.com , twitter.com . I valori del dizionario sono matrici di identificatori univoci per ciascun provider di identità associato all'account. Ad esempio, auth.token.firebase.identities["google.com"][0] contiene il primo ID utente Google associato all'account.
firebase.sign_in_provider Il provider di accesso utilizzato per ottenere questo token. Può essere una delle seguenti stringhe: custom , password , phone , anonymous , google.com , facebook.com , github.com , twitter.com .
firebase.tenant Il tenantId associato all'account, se presente. ad esempio tenant2-m6tyz

Se si utilizza l'autenticazione personalizzata, auth.token contiene anche eventuali attestazioni personalizzate specificate dallo sviluppatore.

Tutti questi valori possono essere utilizzati all'interno delle regole. Ad esempio, per limitare l'accesso agli account Google associati a un indirizzo gmail.com, potremmo aggiungere la regola:

{
  "rules": {
    ".read": "auth != null",
    "gmailUsers": {
      "$uid": {
        ".write": "auth.token.email_verified == true && auth.token.email.matches(/.*@gmail.com$/)"
      }
    }
  }
}

Per completezza, sono inclusi anche i seguenti campi, in auth.token , ma è improbabile che siano utili per le regole.

Campo Descrizione
iss L'emittente del token.
aud Il pubblico del token.
auth_time L'ultima volta che l'utente si è autenticato con una credenziale utilizzando il dispositivo che riceve il token.
iat L'ora in cui è stato emesso il token.
exp L'ora in cui il token scade.

$posizione

Una variabile che può essere utilizzata per fare riferimento alla chiave di una $location utilizzata in precedenza in una struttura di regole.

Quando hai una $location nella struttura delle regole, puoi utilizzare una variabile $ corrispondente all'interno dell'espressione della regola per ottenere il nome del bambino effettivo che viene letto o scritto. Supponiamo quindi di voler fornire a ogni utente l'accesso in lettura e scrittura alla propria posizione /users/<user> . Potremmo usare:

{
  "rules": {
    "users": {
      "$user": {
        ".read": "auth.uid === $user",
        ".write": "auth.uid === $user"
      }
    }
  }
}

Quando un client tenta di accedere /users/barney , la posizione predefinita $user corrisponderà a $user uguale a "barney". Quindi la regola .read controllerà se auth.uid === 'barney' . Di conseguenza, la lettura di /users/barney avrà successo solo se il client è autenticato con l'uid "barney".

Ora

Contiene il numero di millisecondi dall'epoca Unix secondo i server Firebase Realtime Database.

La variabile now contiene il numero di millisecondi dall'epoca UNIX secondo i server Firebase Realtime Database. Ad esempio, potresti usarlo per verificare che l'ora created da un utente non sia mai impostata su un'ora futura:

{
  "rules": {
    "users": {
      "$user": {
        "created": {
          ".validate": "newData.val() < now"
        }
      }
    }
  }
}

radice

Un RuleDataSnapshot corrispondente ai dati correnti nella radice del tuo Firebase Realtime Database.

La variabile root ti fornisce un RuleDataSnapshot corrispondente ai dati correnti nella root del tuo Firebase Realtime Database. Puoi usarlo per leggere tutti i dati nel tuo database nelle espressioni delle regole. Ad esempio, se volessimo consentire agli utenti di leggere /comments solo se il loro /users/<id>/active fosse impostato su true, potremmo utilizzare:

{
  "rules": {
    "comments": {
      ".read": "root.child('users').child(auth.uid).child('active').val() == true"
    }
  }
}

Quindi, se /users/barney/active contenesse il valore true, un utente autenticato con l'uid "barney" potrebbe scrivere sul nodo /comments .

dati

Un RuleDataSnapshot corrispondente ai dati correnti nel Firebase Realtime Database nella posizione della regola attualmente in esecuzione.

La variabile data fornisce un RuleDataSnapshot corrispondente ai dati correnti nella posizione del database della regola attualmente in esecuzione (al contrario di root, che fornisce i dati per la radice del database).

Quindi, ad esempio, se desideri consentire a qualsiasi client di accedere a /users/<user> se /users/<user>/public è impostato su true, potresti utilizzare:

{
  "rules": {
    "users": {
      "$user": {
        ".read": "data.child('public').val() == true"
      }
    }
  }
}

La variabile data è disponibile nelle regole .read , .write e .validate .

newData

Un RuleDataSnapshot corrispondente ai dati che risulteranno se la scrittura è consentita.

Per le regole .write e .validate , la variabile newData fornisce un RuleDataSnapshot corrispondente ai dati che risulteranno se la scrittura è consentita (si tratta di una "fusione" dei dati esistenti più i nuovi dati in fase di scrittura). Quindi, se volessi assicurarti che ogni utente abbia un nome ed un'età, potresti utilizzare:

{
  "rules": {
    "users": {
      "$user": {
        ".read": true,
        ".write": true,
        ".validate": "newData.hasChildren(['name', 'age'])"
      }
    }
  }
}

Poiché newData unisce dati esistenti e nuovi dati, si comporta correttamente anche per aggiornamenti "parziali". Per esempio:

var fredRef = firebase.database().ref("users/fred");
// Valid since we have a name and age.
fredRef.set({ name: "Fred", age: 19 });
// Valid since we are updating the name but there's already an age.
fredRef.child("age").set(27);
// Invalid since the .validate rule will no longer be true.
fredRef.child("name").remove();

La variabile newData non è disponibile nelle regole .read poiché non vengono scritti nuovi dati. Dovresti semplicemente usare i dati .

RuleDataSnapshot: metodi

val()

Ottiene il valore primitivo ( string , number , boolean o null ) da RuleDataSnapshot .

Valore restituito : ( String , Number , Boolean , Null ) - Il valore primitivo di questo RuleDataSnapshot .

A differenza di DataSnapshot.val() , chiamare val() su un RuleDataSnapshot che ha dati figli non restituirà un oggetto contenente i figli. Restituirà invece un valore sentinella speciale. Ciò garantisce che le regole possano sempre funzionare in modo estremamente efficiente.

Di conseguenza, devi sempre utilizzare child() per accedere ai figli (ad esempio data.child('name').val() , non data.val().name ).

Questo esempio consente la lettura solo se il figlio isReadable è impostato su true nella posizione da leggere.

".read": "data.child('isReadable').val() == true"

bambino()

Ottiene un RuleDataSnapshot per la posizione nel percorso relativo specificato.

Argomenti : childPath String : un percorso relativo alla posizione dei dati figlio.

Valore restituito : RuleDataSnapshot : RuleDataSnapshot per la posizione figlio.

Il percorso relativo può essere un semplice nome figlio (ad esempio 'fred') o un percorso più profondo separato da barre (ad esempio 'fred/nome/primo'). Se la posizione secondaria non contiene dati, viene restituito un RuleDataSnapshot vuoto.

Questo esempio consente la lettura solo se il figlio isReadable è impostato su true nella posizione da leggere.

".read": "data.child('isReadable').val() == true"

genitore()

Ottiene un RuleDataSnapshot per la posizione padre.

Valore restituito : RuleDataSnapshot : RuleDataSnapshot per la posizione padre.

Se questa istanza fa riferimento alla radice del tuo Firebase Realtime Database, non ha un genitore e parent() fallirà, causando il salto dell'espressione della regola corrente (come errore).

Questo esempio consente la lettura solo se il fratello isReadable è impostato su true.

".read": "data.parent().child('isReadable').val() == true"

hasChild(percorsofiglio)

Restituisce vero se il figlio specificato esiste.

Argomenti : childPath String - Un percorso relativo alla posizione di un potenziale figlio.

Valore restituito : booleano : true se i dati esistono nel percorso figlio specificato; altrimenti false .

Questo esempio consente la scrittura dei dati solo se contengono un "nome" figlio.

".validate": "newData.hasChild('name')"

haFigli([figli])

Verifica l'esistenza dei figli.

Argomenti : children Array opzionale - Un array di chiavi figlio che devono esistere tutte.

Valore restituito : Boolean - true se (i figli specificati) esistono; altrimenti false .

Se non vengono forniti argomenti, restituirà true se RuleDataSnapshot ha dei figli. Se viene fornito un array di nomi figlio, restituirà true solo se tutti i figli specificati esistono in RuleDataSnapshot .

Questo esempio consente la scrittura dei dati solo se contengono uno o più figli.

".validate": "newData.hasChildren()"

Questo esempio consente la scrittura dei dati solo se contengono figli "nome" ed "età".

".validate": "newData.hasChildren(['name', 'age'])"

esiste()

Restituisce vero se questo RuleDataSnapshot contiene dati.

Valore restituito : Boolean - true se RuleDataSnapshot contiene dati; altrimenti false .

La funzione esiste restituisce true se questo RuleDataSnapshot contiene dati. È puramente una funzione di comodità poiché data.exists() è equivalente a data.val() != null .

Questo esempio consente una scrittura in questa posizione purché non siano presenti dati esistenti.

".write": "!data.exists()"

getPriorità()

Ottiene la priorità dei dati in RuleDataSnapshot .

Valore restituito : ( String , Number , Null ) - La priorità dei dati in questo RuleDataSnapshot .

Questo esempio garantisce che i nuovi dati scritti abbiano una priorità

".validate": "newData.getPriority() != null"

èNumero()

Restituisce vero se questo RuleDataSnapshot contiene un valore numerico.

Valore restituito : Boolean : true se i dati sono numerici; altrimenti false .

Questo esempio garantisce che i nuovi dati scritti abbiano un'"età" secondaria con un valore numerico.

".validate": "newData.child('age').isNumber()"

èStringa()

Restituisce true se questo RuleDataSnapshot contiene un valore stringa.

Valore restituito : Boolean - true se i dati sono una String ; altrimenti false .

Questo esempio garantisce che i nuovi dati scritti abbiano un "nome" figlio con un valore stringa.

".validate": "newData.child('name').isString()

èBooleano()

Restituisce vero se questo RuleDataSnapshot contiene un valore booleano.

Valore restituito : Boolean - true se i dati sono Boolean ; altrimenti false .

Questo esempio garantisce che i nuovi dati scritti abbiano un figlio "attivo" con un valore booleano.

".validate": "newData.child('active').isBoolean()"

Stringa: proprietà

lunghezza

Restituisce la lunghezza della stringa.

Valore restituito : Number : il numero di caratteri nella stringa.

Questo esempio richiede che la stringa contenga almeno 10 caratteri.

".validate": "newData.isString() && newData.val().length >= 10"

Stringa: metodi

contiene(sottostringa)

Restituisce vero se la stringa contiene la sottostringa specificata.

Argomenti : substring String - Una sottostringa da cercare.

Valore restituito : Boolean - true se la stringa contiene la sottostringa specificata; altrimenti false .

Questo esempio richiede che i dati siano una stringa contenente "@".

".validate": "newData.isString() && newData.val().contains('@')"

iniziaCon(sottostringa)

Restituisce vero se la stringa inizia con la sottostringa specificata.

Argomenti : substring String - Una sottostringa da cercare all'inizio.

Valore restituito : Boolean - true se la stringa contiene la sottostringa specificata; altrimenti false .

Questo esempio consente l'accesso in lettura se auth.token.identifier inizia con "internal-"

".read": "auth.token.identifier.beginsWith('internal-')"

terminaCon(sottostringa)

Restituisce vero se la stringa termina con la sottostringa specificata.

Argomenti : substring String - Una sottostringa da cercare alla fine.

Valore restituito : Boolean - true se la stringa termina con la sottostringa specificata; altrimenti false .

Questo esempio consente l'accesso in lettura se auth.token.identifier termina con "@company.com"

".read": "auth.token.identifier.endsWith('@company.com')"

sostituire(sottostringa, sostituzione)

Restituisce una copia della stringa con tutte le istanze di una sottostringa specificata sostituite con la stringa sostitutiva specificata.

Argomenti : substring String - Una sottostringa da cercare. replacement String : una stringa con cui sostituire la sottostringa.

Valore restituito : String : la nuova stringa dopo aver sostituito la sottostringa con la sostituzione.

Il metodo replace() differisce leggermente dal metodo JavaScript replace() in quanto sostituisce tutte le istanze di una sottostringa specificata con la stringa di sostituzione specificata, non solo la prima istanza.

Poiché i punti non sono consentiti nelle chiavi, è necessario eseguire l'escape delle stringhe con punti prima di memorizzarle. Un esempio di ciò potrebbe essere con gli indirizzi e-mail. Supponiamo di avere un elenco di indirizzi email autorizzati nel nostro nodo /whitelist/ :

{
 "user": {
   "$uid": {
     "email": <email>
   }
 },
 "whitelist": {
   "fred@gmail%2Ecom": true,
   "barney@aol%2Ecom": true
 }
}

Possiamo creare una regola che consenta agli utenti di essere aggiunti solo se la loro email è nel nodo /whitelist/ :

{
  "rules": {
    "users": {
      "$uid": {
        ".read": "true",
        ".write": "root.child('whitelist').child(newData.child('email').val().replace('.', '%2E')).exists()"
      }
    }
  }
}

inLowerCase()

Restituisce una copia della stringa convertita in minuscolo.

Valore restituito : String : la stringa convertita in lettere minuscole.

Questo esempio consente l'accesso in lettura se auth.token.identifier è presente tutto in lettere minuscole in /users .

".read": "root.child('users').child(auth.token.identifier.toLowerCase()).exists()"

inMaiuscolo()

Restituisce una copia della stringa convertita in maiuscolo.

Valore restituito : String : la stringa convertita in maiuscolo.

Questo esempio consente l'accesso in lettura se auth.token.identifier è tutto maiuscolo in /users .

".read": "root.child('users').child(auth.token.identifier.toUpperCase()).exists()"

corrispondenze(regex)

Restituisce vero se la stringa corrisponde al valore letterale dell'espressione regolare specificato.

Valore restituito : Boolean - true se la stringa corrisponde al valore letterale dell'espressione regolare, regex; altrimenti false .

Consulta la documentazione completa sulle regole regex .

Operatori

+ (aggiungi)

Utilizzato per aggiungere variabili o per concatenare stringhe.

L'esempio seguente garantisce che il nuovo valore incrementi il ​​valore esistente esattamente di uno. Questo è utile per implementare un contatore:

".write": "newData.val() === data.val() + 1"
".validate": "root.child('room_names/' + $room_id).exists()"

- (negare o sottrarre)

Utilizzato per negare un valore o sottrarre due valori in un'espressione di regole.

Questa regola di convalida verifica che il nuovo valore sia l'inverso di un valore figlio nella posizione:

".validate": "newData.val() === -(data.child('quantity').val())"

L'esempio seguente utilizza la sottrazione per garantire che possano essere letti solo i messaggi degli ultimi dieci minuti:

".read": "newData.child('timestamp').val() > (now - 600000)"

* (moltiplicare)

Utilizzato per moltiplicare le variabili in un'espressione di regole.

Questa regola di convalida verifica se il nuovo valore è uguale al prodotto di prezzo e quantità (due valori esistenti):

".validate": "newData.val() === data.child('price').val() * data.child('quantity').val()"

/ (dividere)

Utilizzato per dividere le variabili in un'espressione di regole.

Nell'esempio seguente, la regola di convalida garantisce che i dati archiviati siano la media del totale dei dati archiviati altrove:

".validate": "newData.val() === data.parent().child('sum').val() / data.parent().child('numItems').val()"

% (modulo)

Utilizzato per trovare il resto della divisione di una variabile per un'altra in un'espressione di regole.

Questa regola convalida che solo i numeri pari possono essere scritti:

".validate": "newData.val() % 2 === 0"

=== (uguale)

Utilizzato per verificare se due variabili in un'espressione di regole hanno lo stesso tipo e valore.

La regola seguente utilizza l'operatore === per concedere l'accesso in scrittura solo al proprietario dell'account utente. L'UID dell'utente deve corrispondere esattamente alla chiave ( $user_id ) affinché la regola valuti true.

"users": {
  ".write": "$user_id === auth.uid"
}

!== (non uguale)

Utilizzato per verificare se due variabili in un'espressione di regole non sono uguali.

La seguente regola di lettura garantisce che solo gli utenti registrati possano leggere i dati:

".read": "auth !== null"

&& (E)

Restituisce vero se entrambi gli operandi sono veri. Utilizzato per valutare più condizioni in un'espressione di regole.

La seguente regola di convalida verifica che i nuovi dati siano una stringa inferiore a 100 caratteri:

".validate": "newData.isString() && newData.val().length < 100"

|| (O)

Restituisce vero se un operando nell'espressione delle regole è vero.

In questo esempio, possiamo scrivere finché non esistono dati vecchi o nuovi. In altre parole, possiamo scrivere se stiamo cancellando o creando dati, ma non aggiornando i dati.

".write": "!data.exists() || !newData.exists()"

! (NON)

Restituisce vero se il suo singolo operando è falso. Nelle espressioni di regole, il ! L'operatore viene spesso utilizzato per verificare se i dati sono stati scritti in una posizione.

La seguente regola consente l'accesso in scrittura solo se non sono presenti dati nella posizione specificata:

".write": "!data.exists()"

> (maggiore di)

Utilizzato per verificare se un valore è maggiore di un altro valore in un'espressione di regole.

Questa regola di validazione verifica che la stringa da scrivere non sia una stringa vuota:

".validate": "newData.isString() && newData.val().length > 0"

< (meno di)

Utilizzato per verificare se un valore è inferiore a un altro valore in un'espressione di regole.

Questa regola di convalida verifica che una stringa contenga meno di 20 caratteri:

".validate": "newData.isString() && newData.val().length < 20"

>= (maggiore o uguale a)

Utilizzato per verificare se un valore è maggiore o uguale a un altro valore in un'espressione di regole.

Questa regola di validazione verifica che la stringa da scrivere non sia una stringa vuota:

".validate": "newData.isString() && newData.val().length >= 1"

<= (minore o uguale a)

Utilizzato per verificare se un valore è inferiore o uguale a un altro valore in un'espressione di regole.

Questa regola di convalida garantisce che nuovi dati non possano essere aggiunti in futuro:

".validate": "newData.val() <= now"

? (operatore ternario)

Utilizzato per valutare un'espressione di regole condizionali.

L'operatore ternario accetta tre operandi. L'operando prima del ? è la condizione. Se la condizione risulta vera, viene valutato il secondo operando. Se la condizione è falsa, viene valutato il terzo operando.

Per la seguente regola di convalida, il nuovo valore può essere un numero o un valore booleano. Se è un numero, deve essere maggiore di 0.

".validate": "newData.isNumber() ? newData.val() > 0 : newData.isBoolean()"