javascript - Angular 6 AngularFireAuth check if user is logged in before page rendered
问题描述
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>
解决方案
您可能很久以前就想到了这一点,但其他人可能会想知道。我选择对 angularFireAuth 的 authState 进行检查。如果它为空,则您已注销。然后您可以按照Ryan Chenkie 的 Medium 文章中的说明使用路由守卫
@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));
}
...
}
推荐阅读
- c++ - 将 char 传递给具有 char 参数的函数有什么问题
- java - 如何处理 setOnClickListener 以在 android 中动态添加按钮?
- excel - 在 VBA 中抓取谷歌搜索结果
- flutter - 接收异常:在 null 上调用了 getter 'id'
- python - 如何在dask中使用所有cpu?
- python - Pytorch GRU 错误 RuntimeError:大小不匹配,m1:[1600 x 3],m2:[50 x 20]
- php - HTML/CSS/PHP 联系表未提交
- php - TYPO3 v10 后端环境中的图像处理
- android - Android NDK:如何抑制“应用程序只有 32 位库”警告
- java - 当传感器事件发生变化时,如何多次增加变量?