Skip to content
Advertisement

How to set Firebase rules for anonymous users to only read and write their own data

I would like anonymous users to be able to only read and write their own data. I have the below as my security rules, but am getting a cannot read error in the simulator and the app.

I’m not sure that I’m going about it the right way. My main objective is to nest new assessments of the same user under their uid’s and make it so they can only read, write and update their own assessments.

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

This is what my branch currently looks like

https://i.stack.imgur.com/u4DEI.png

This is what I think it should look like to accomplish what I need. Ideal Database structure

auth.gaurd.ts

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { AuthService } from "../../shared/service/auth.service";
import { Observable } from 'rxjs';
import * as firebase from 'firebase';
@Injectable({
  providedIn: 'root'
})

export class AuthGuard implements CanActivate {
  
  uid: string;
  constructor(
    public authService: AuthService,
    public router: Router
  ){ }

  canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    this.authStateListener();
    return true;
  }
  authStateListener() {
    // [START auth_state_listener]
    firebase.auth().onAuthStateChanged((user) => {
      if (user) {
        // User is signed in, see docs for a list of available properties
        this.uid = user.uid;
        console.log("user"+user.isAnonymous)
        console.log("uid"+this.uid)
      } else {
        // User is signed out
        return  firebase.auth().signOut().then(() => {
          localStorage.removeItem('user');
          this.router.navigate(['sign-in']);
        })
      }
    });

}
}

auth.service.ts

import { Injectable, NgZone, ViewChild, ElementRef, Component } from '@angular/core';
import { User } from "../service/user";
import { auth } from 'firebase/app';
import { AngularFireAuth } from "@angular/fire/auth";
import { AngularFirestore, AngularFirestoreDocument } from '@angular/fire/firestore';
import { ActivatedRoute, Router } from "@angular/router"; 
import * as firebase from 'firebase';
import "firebase/auth";


@Injectable({
  providedIn: 'root'
})



export class AuthService {
  userData: any; // Save logged in user data
 @ViewChild('btnLogin') btnLogin: HTMLButtonElement;


  constructor(
    public afs: AngularFirestore,   // Inject Firestore service
    public afAuth: AngularFireAuth, // Inject Firebase auth service
    public router: Router,
    private actRoute: ActivatedRoute,
    public ngZone: NgZone // NgZone service to remove outside scope warning
    
  ) {
    

  }

  anonymousSignIn(){
    firebase.auth().signInAnonymously()
    .then(()=>{
      this.router.navigate(['assessment']);
      console.log("clicking")
    }).catch((error) => {
      var errorCode = error.code;

      var errorMessage = error.message;
      console.log("error here")
    });
  }

**This is the code to push, read, update and delete branches in Firebase. The ReadAssessment list should display all data that the anonymous user owns in order for them to read it. ** fire-assessment.service.ts

import { AuthGuard } from './../shared/guard/auth.guard';
import { Injectable } from '@angular/core';
import {AngularFireDatabase, AngularFireList,  AngularFireObject} from '@angular/fire/database';
import * as firebase from 'firebase';
import {Business} from '../models/business';
import { ActivatedRoute, Router } from '@angular/router';
import { map } from 'rxjs/internal/operators/map';
import { isNgTemplate } from '@angular/compiler';



@Injectable({
  providedIn: 'root'
})
export class FireAssessmentService {
  assessmentsRef: AngularFireList<any>; // Reference to Assessment data list, its an Observable
  assessmentRef: AngularFireObject<any>; // Reference to assessment object
  public database = firebase.database();
  public UserAssessmentInput;
  public ref;
  public actRoute: ActivatedRoute;
  public router: Router;
  public auth: AuthGuard;
  
  


  constructor(private db: AngularFireDatabase) {
   
   }
CreateAssessment(business: Business ){
  const key = this.database.ref('/users').push().key;
  this.database.ref('/users').child(key).set(
    ///this.assessmentsRef.ref('/users').push(
    {
      busiName: business.busiName
       });
    
  }
  
  
  ReadAssessment(id: string){
    this.assessmentRef = this.db.object('users/' + id);
    return this.assessmentRef;
  }
  
  
  ReadAssessmentsList(){
    this.assessmentsRef = this.db.list('users/');
    return this.assessmentsRef;
  }
  
   UpdateAssessments (business: Business){
    this.assessmentRef.update({
    busiName: business.busiName
      });
  }
  
  DeleteAssessment(){
    this.assessmentRef = this.db.object('users/');
    this.assessmentRef.remove();
  }

business.ts

export interface Business {
    $key: string;
    busiName: string;
    
    }

Advertisement

Answer

Right now you’re creating data with this:

const key = this.database.ref('/users').push().key;
this.database.ref('/users').child(key).set({
  busiName: business.busiName
});

When you call push() Firebase generates a new unique location, which is the key starting with -M... in your JSON.

That value is not the UID of the current user, so these rules then don’t allow the user to read or write it:

"users": {
  "$uid": {
      ".write": "$uid === auth.uid";
       ".read": "$uid === auth.uid";  
  }
}

Instead you should write the data under a node using the user’s UID as the key. That’d look something like:

const key = this.database.ref('/users').push().key;
if (firebase.auth().currentUser) {
  const key = firebase.auth().currentUser.uid;
  this.database.ref('/users').child(key).set({
    busiName: business.busiName
  });
}
else {
  console.error("No current user while trying to write business name");
}
Advertisement