Angular 16集成Firebase谷歌登录报错及路由守卫方案求助
问题解决与完整实现方案
一、GoogleAuthProvider报错修复
报错核心原因是仅导入了firebase/compat/app基础模块,未引入Firebase Auth的兼容模块,导致firebase.auth对象未定义。
修复步骤:
- 补充Auth兼容模块导入
在AuthService的导入区域添加:
import "firebase/compat/auth";
添加后firebase.auth.GoogleAuthProvider即可被正常识别调用。
- 完善用户数据保存逻辑
原updateUserData方法缺少数据持久化操作,补充如下:
private updateUserData(user: any) { const userRef: AngularFirestoreDocument<User> = this.afs.doc(`users/${user.uid}`); const data = { uid: user.uid, email: user.email, displayName: user.displayName, photoURL: user.photoURL }; // 用merge模式保存,避免覆盖用户后续修改的自定义数据 return userRef.set(data, { merge: true }); }
- 优化登录方法(可选)
也可通过动态导入方式创建Provider,避免依赖全局firebase对象:
async googleSignin() { const { GoogleAuthProvider } = await import('firebase/auth'); const provider = new GoogleAuthProvider(); // 可选:强制用户选择账号,避免自动登录上次账号 provider.setCustomParameters({ prompt: 'select_account' }); const credential = await this.afAuth.signInWithPopup(provider); await this.updateUserData(credential.user); this.router.navigate(['/dashboard']); }
二、公共路由守卫实现(限制已登录用户访问着陆页)
创建PublicGuard,拦截已登录用户访问公共页面:
1. 编写守卫代码
// src/app/guards/public.guard.ts import { Injectable } from '@angular/core'; import { CanActivate, Router } from '@angular/router'; import { AuthService } from '../services/auth.service'; import { map, take } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class PublicGuard implements CanActivate { constructor(private authService: AuthService, private router: Router) {} canActivate() { return this.authService.user$.pipe( take(1), map(user => { // 已登录用户直接跳转到主页,禁止访问公共页 if (user) { this.router.navigate(['/dashboard']); return false; } // 未登录用户允许访问 return true; }) ); } }
2. 路由配置中应用守卫
修改app-routing.module.ts,为着陆页绑定守卫:
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { PublicGuard } from './guards/public.guard'; import { LandingComponent } from './components/landing/landing.component'; import { DashboardComponent } from './components/dashboard/dashboard.component'; const routes: Routes = [ { path: '', component: LandingComponent, canActivate: [PublicGuard] }, { path: 'dashboard', component: DashboardComponent }, // 其他路由配置... ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule {}
三、修复后的完整AuthService代码
import { Injectable } from '@angular/core'; import { Router } from '@angular/router'; import firebase from "firebase/compat/app"; import "firebase/compat/auth"; import { AngularFireAuth } from '@angular/fire/compat/auth'; import { AngularFirestore, AngularFirestoreDocument } from '@angular/fire/compat/firestore'; import { Observable, of } from 'rxjs'; import { switchMap } from 'rxjs/operators'; import { User } from '../models/user.model'; @Injectable({ providedIn: 'root' }) export class AuthService { user$: Observable<User | null | undefined>; 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); } }) ) } async googleSignin() { const provider = new firebase.auth.GoogleAuthProvider(); provider.setCustomParameters({ prompt: 'select_account' }); const credential = await this.afAuth.signInWithPopup(provider); await this.updateUserData(credential.user); this.router.navigate(['/dashboard']); } private async updateUserData(user: any) { const userRef: AngularFirestoreDocument<User> = this.afs.doc(`users/${user.uid}`); const data = { uid: user.uid, email: user.email, displayName: user.displayName, photoURL: user.photoURL, lastLogin: new Date() }; return userRef.set(data, { merge: true }); } async signOut() { await this.afAuth.signOut(); this.router.navigate(['/']); } }
内容的提问来源于stack exchange,提问作者Manuel Quiroga
相关产品推荐
相关产品推荐

