Angular Firestore Admin Auth Guard - PullRequest
       10

Angular Firestore Admin Auth Guard

0 голосов
/ 06 сентября 2018

Я пытаюсь запретить обычным пользователям доступ к административной части моего приложения. В настоящее время свойство admin в документе Firestore имеет значение 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 голосов
/ 06 сентября 2018

Вы не можете полагаться на инициализацию uid при синхронном доступе к нему, потому что он будет заполнен firebase, когда пользователь (внутренне) аутентифицирован. Я предпочел бы рассматривать это как наблюдаемое и обращаться к нему асинхронно.

Итак, давайте сделаем это видимым, создадим 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(). Всякий раз, когда изменяется глобальное состояние аутентификации, authState будет испускать элемент. Когда этот элемент определен (таким образом, пользователь проходит проверку подлинности), будет сделан запрос в firestore, чтобы получить документ пользователя. Когда authState не определен (таким образом, пользователь не аутентифицирован), будет выдан NEVER, что означает, что ничего не будет возвращено и наблюдаемое не будет прекращено.

Теперь используйте этот класс в вашей охране:

@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),
    );
  }
}

Мы сохраняем сложность внутри службы аутентификации, и, как следствие, аутентификация аутентификации становится довольно глупой. Он подписывается на getUser и перенаправляет на вход в систему, когда пользователь не определен (не аутентифицирован) или не является администратором.

...