Angular Firestore管理员身份验证防护

时间:2018-09-06 02:35:48

标签: angular firebase firebase-authentication angular5 google-cloud-firestore

我正在尝试阻止普通用户访问应用程序的管理员端。当前,Firestore文档上的admin属性为true或false。如果为false,则在尝试访问主页时应将其重定向到主页,否则允许用户继续访问该页面。

这是我的admin-auth-guard.service.ts

  userDoc: AngularFirestoreDocument<User>;
  user: Observable<User>;

  constructor(private afAuth: AngularFireAuth,
              private afs: AngularFirestore,
              private router: Router) {}

  canActivate() {
    this.userDoc = this.afs.doc('users/' + this.afAuth.auth.currentUser.uid);
    this.user = this.userDoc.valueChanges();
    return this.user.map(role => {
      if (role.admin)
          return true
        this.router.navigate(['/']);
          return false;        
    });
  }

我相信代码会起作用,尽管在初始化Admin Auth Guard时,请求发生得太快,并且uid为null。

我收到此错误:

ERROR Error: Uncaught (in promise): TypeError: Cannot read property 'uid' of null

TypeError: Cannot read property 'uid' of null

Firestore和angular似乎是一个小众话题,两者的信息不多。任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:1)

您不能依赖于selected的同步访问,因为当用户(内部)通过身份验证时,firebase将填充它。我宁愿将其视为可观察并异步访问。

因此,让它变得可观察,创建一个uid文件:

auth.service.ts

因此,一个人可以订阅Injectable() export class FirebaseAuthService { constructor( private angularFireAuth: AngularFireAuth, private angularFirestore: AngularFirestore, ) { } getUser(): Observable<any> { return this.angularFireAuth.authState.pipe( mergeMap(authState => { if (authState) { return from(this.angularFirestore.doc(`users/${authState.uid}`).get()); } else { return NEVER; } }) ); } // is logged in? // signin // more auth related methods } 。每当全局身份验证状态更改时,getUser()将发出一个项目。定义此项目后(从而对用户进行身份验证),将向firestore发出请求以检索用户文档。当authState未定义(因此用户未通过身份验证)时,将发出authState,这意味着将不返回任何内容,并且可观察项也不会终止。

现在在您的身份验证防护中使用此类:

NEVER

我们将复杂性保留在auth服务内部,结果,auth防护变得很笨。它订阅@Injectable() export class AdminAuthGuardService implements CanActivate { constructor( private router: Router, private firebaseAuthService: FirebaseAuthService, ) { } canActivate() { return this.firebaseAuthService.getUser().pipe( map(user => { if (!user || !user.admin) { // noinspection JSIgnoredPromiseFromCall this.router.navigate(['/login']); return false; } return true; }), take(1), ); } } 并在用户未定义(未验证)或不是管理员时重定向到登录。