Angular 6 AngularFireAuth check if user is logged in before page rendered

橙三吉。 提交于 2019-12-07 13:37:20

问题


I have set up a new angular 6 project with Firebase auth and Cloud Fire Store. There is a login page where you can login via google and the user data is saved in Firestore (code below). My only issue is how I can check if the user is already logged in, is there any best practice?

At the moment im fetching the user data async, but then the navigation is flickering. For one second there is the login button, then it switches to the logout button. Is there good way to check the login state before it renders the page?

User.ts

export interface User {
  uid: string;
  email: string;
}

auth.service.ts

import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import * as firebase from 'firebase/app';
import { AngularFireAuth } from 'angularfire2/auth';
import { AngularFirestore, AngularFirestoreDocument } from 'angularfire2/firestore';
import { Observable, of } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { User } from './user';

@Injectable({
  providedIn: 'root'
})
export class AuthService {

  user: Observable<User>;

  constructor(private afAuth: AngularFireAuth, private afs: AngularFirestore, private router: Router) {
    this.user = this.afAuth.authState.pipe(
        switchMap(user => {
          if (user) {
            return this.afs.doc<User>(`users/${user.uid}`).valueChanges();
          } else {
            return of(null);
          }
        }))
  }

  public googleLogin() {
    const provider = new firebase.auth.GoogleAuthProvider()
    return this.oAuthLogin(provider);
  }

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

  private oAuthLogin(provider) {
    return this.afAuth.auth.signInWithPopup(provider)
      .then((credential) => {
        this.updateUserData(credential.user)
      })
  }

  private updateUserData(user) {
    const userRef: AngularFirestoreDocument<any> = this.afs.doc(`users/${user.uid}`);
    const data: User = {
      uid: user.uid,
      email: user.email
    }
    return userRef.set(data, { merge: true })
  }

}

navigation.component.ts

import { Component, OnInit } from '@angular/core';
import { AuthService } from '../core/auth.service';
import { AngularFireAuth } from 'angularfire2/auth';

@Component({
  selector: 'app-navigation',
  templateUrl: './navigation.component.html',
  styleUrls: ['./navigation.component.scss']
})
export class NavigationComponent implements OnInit {

  constructor(public auth: AuthService) { }

  ngOnInit() {}

}

auth.service.ts

<div *ngIf="auth.user | async; then loggedIn else loggedOut"></div>

<ng-template #loggedOut>
    <li  class="nav-item d-none d-md-inline-block pl-2 pr-0">
        <a class="btn btn-sm btn-primary u-btn-primary u-btn-pill transition-3d-hover" href="/login">
            Login
        </a>
    </li>
</ng-template>

<ng-template #loggedIn>
    <li  class="nav-item d-none d-md-inline-block pl-2 pr-0">
        <a class="btn btn-sm btn-primary u-btn-primary u-btn-pill transition-3d-hover" (click)="auth.signOut()">
            Logout
        </a>
    </li>
</ng-template>

回答1:


You probably figured this out a long time ago but someone else might wonder. I chose to do a check against the authState of angularFireAuth. If it's null, then you're logged out. Then You can use route guards as explained in Ryan Chenkie's Medium article

@Injectable()
export class FirebaseAuthService {
private authState: Observable<firebase.User>
private currentUser: firebase.User = null;

constructor(
  public afAuth: AngularFireAuth,
  private http: HttpClient,
  private localStorage: LocalStorageService,
  private router: Router,
  private snackBar: MatSnackBar) {
  this.authState = this.afAuth.authState;

this.authState.subscribe(user => {
  if (user) {
    this.currentUser = user;
    this.localStorage.storeSimple('userData', user)
    this.openSnackBar('Successfully authenticated');
    console.log('AUTHSTATE USER', user)
    this.router.navigate(['home']);
  } else {
    console.log('AUTHSTATE USER EMPTY', user)
    this.currentUser = null;
  }
},
  err => {
    this.openSnackBar(`${err.status} ${err.statusText} (${err.error.message})`, 'Please try again')
  });
 }

 isAuthenticated(): boolean {
   return this.authState !== null;
 }

 loginEmail(email, password, route) {
   this.afAuth.auth.signInWithEmailAndPassword(email, password).catch(error => {
   let errorCode = error.code;
   let errorMessage = error.message;
   this.openSnackBar(error, 'OK')
 });
}

logout() {
  this.afAuth.auth.signOut()
  .then(response => this.openSnackBar('Signed out'))
  .catch(error => this.openSnackBar('Error signing out: ' + error));
}

...
}



回答2:


You can use can activate routes concept present in routing module of angular..... In this concept it just call the injectable service every time when ever the routing or navigation of the page happen.... There you can also check whether the user have permission to view the page or not



来源:https://stackoverflow.com/questions/50572683/angular-6-angularfireauth-check-if-user-is-logged-in-before-page-rendered

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!