Firestore security

Server configuration

Go in the Firebase Console

Go to Database - Rules and add the following rule to require that access to all database objects requires a logged in user.

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if request.auth.uid != null;
    }
  }
}

Client configuration

Inside src/app create a new folder _services.

Generate a new service ins _services named auth

import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { AngularFireAuth } from '@angular/fire/auth';
import { auth } from 'firebase';

@Injectable({
  providedIn: 'root'
})
export class AuthService {
  private _isLogIn = new BehaviorSubject(false);
  private _user: firebase.User;

  constructor(public afAuth: AngularFireAuth) {
    afAuth.authState.subscribe(user => {
      const loggedIn = !!user;
      this._user = user;

      console.log(`user is ${loggedIn ? '' : 'not '}logged in`);
      this._isLogIn.next(loggedIn);
    });
  }

  get isLogIn(): Observable<boolean> {
    return this._isLogIn.asObservable();
  }

  get user() {
    return this._user;
  }

  login() {
    this.afAuth.auth.signInWithPopup(new auth.GoogleAuthProvider()).then(
      userCredential => {
        this._user = userCredential.user;
        if (this._user) {
          console.log('Succesfull login');
        } else {
          console.log('Failed login');
        }
      },
      error => {
        console.log('Error during login');
        console.log(error);
        this._isLogIn.next(false);
      }
    );
  }

  logout() {
    this.afAuth.auth.signOut();
  }
}

Change app.component.ts remove the direct usage of AngularFireAuth and use the new service

import { Component } from '@angular/core';
import { Observable } from 'rxjs';
import { AngularFirestore } from '@angular/fire/firestore';
import { AuthService } from './_services/auth.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'JobSearchLog';
  items: Observable<any[]>;

  constructor(db: AngularFirestore, public authService: AuthService) {
    authService.isLogIn.subscribe(loggedIn => {
      if (loggedIn) {
        this.items = db.collection('items').valueChanges();
      } else {
        this.items = null;
      }
    });
  }
}

Change app.component.html

<mat-toolbar color="primary">
  <mat-toolbar-row>
    <span>JobSearchLog</span>
    <span class="toolbar-spacer"></span>

    <div *ngIf="authService.isLogIn | async; else showLogin">
      <span>Hello {{ authService.user.displayName }}!</span>
      <mat-icon class="toolbar-icon">mail_outline</mat-icon>
      <mat-icon class="toolbar-icon" (click)="authService.logout()">exit_to_app</mat-icon>
    </div>
    <ng-template #showLogin>
      <p>Please login</p>
      <mat-icon class="toolbar-icon" (click)="authService.login()">vpn_key</mat-icon>
    </ng-template>
  </mat-toolbar-row>
</mat-toolbar>

<mat-list>
  <mat-list-item *ngFor="let item of items | async">
    <mat-icon matListIcon>done</mat-icon>
    <h3 matLine> {{item.name}} </h3>
  </mat-list-item>
</mat-list>