#angular #typescript #firebase #firebase-authentication
# #angular #typescript #firebase #firebase-аутентификация
Вопрос:
После применения правил безопасности к моему бэкэнду Firebase я столкнулся с проблемой, связанной с тем, что мои службы в приложении пытаются использовать Firebase до того, как текущий пользователь будет разрешен. Я хотел бы получить некоторую помощь в том, как и где реализовать onAuthStateChanged() на верхнем уровне. Это ошибка, которую я получаю:
ОШИБКА Ошибка: не перехвачено (в обещании): ошибка типа: не удается прочитать свойство ‘uid’ неопределенного типа Ошибка типа: не удается прочитать свойство ‘uid’ неопределенного типа
Я видел, как этот вопрос задавали здесь много раз, но я не могу получить конкретный ответ, который был бы адаптирован к моему приложению.
Это мой файл app.component.ts:
import { Component } from '@angular/core';
import { AuthService } from './auth/services/auth.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(private authService: AuthService) {}
title = 'angular';
}
Мой app.component.html файл:
<mat-toolbar color="primary">
<mat-toolbar-row>
<span class="spacer"></span>
<!-- Account menu -->
<ng-container>
<button mat-icon-button [matMenuTriggerFor]="account"><mat-icon>account_circle</mat-icon></button>
<mat-menu #account="matMenu">
<ng-container *ngIf="authService.userData as user">
<div class="display-name">{{(user.displayName) ? user.displayName : 'User'}}</div>
<div class="email">{{user.email}}</div>
</ng-container>
<mat-divider></mat-divider>
<button class="no-focus" mat-menu-item [routerLink]="['/profile']">Profile</button>
<mat-divider></mat-divider>
<button class="no-focus" mat-menu-item><a (click)="authService.SignOut()">Sign Out</a></button>
</mat-menu>
</ng-container>
</mat-toolbar-row>
</mat-toolbar>
<mat-sidenav-container>
<mat-sidenav #sidenav [opened]="opened">
<mat-nav-list>
...
</mat-nav-list>
</mat-sidenav>
<mat-sidenav-content>
<router-outlet></router-outlet>
</mat-sidenav-content>
</mat-sidenav-container>
И мой файл auth.service.ts:
import { Injectable, NgZone } from '@angular/core';
import { User } from "../models/user";
import { auth } from 'firebase/app';
import { AngularFireAuth } from "@angular/fire/auth";
import { AngularFirestore, AngularFirestoreDocument } from '@angular/fire/firestore';
import { Router } from "@angular/router";
@Injectable({
providedIn: 'root'
})
export class AuthService {
userData: any;
constructor(
public afs: AngularFirestore,
public afAuth: AngularFireAuth,
public router: Router,
public ngZone: NgZone
) {
/* Saving user data in localstorage when
logged in and setting up null when logged out */
this.afAuth.authState.subscribe(user => {
if (user) {
this.userData = user;
localStorage.setItem('user', JSON.stringify(this.userData));
JSON.parse(localStorage.getItem('user'));
} else {
localStorage.setItem('user', null);
JSON.parse(localStorage.getItem('user'));
}
})
}
// Sign in with email/password
SignIn(email, password) {
return this.afAuth.auth.signInWithEmailAndPassword(email, password)
.then((result) => {
this.ngZone.run(() => {
this.router.navigate(['dashboard']);
});
this.SetUserData(result.user);
}).catch((error) => {
window.alert(error.message)
})
}
...
// Sign out
SignOut() {
return this.afAuth.auth.signOut().then(() => {
localStorage.removeItem('user');
this.router.navigate(['sign-in']);
})
}
}
Вот что такое реализация службы аутентификации и использование Firebase:
import { Injectable } from '@angular/core';
import { AngularFirestore, DocumentData, DocumentReference, QuerySnapshot } from '@angular/fire/firestore';
import { Observable } from 'rxjs';
import { AuthService } from '../auth/services/auth.service';
@Injectable({
providedIn: 'root'
})
export class FirestoreService {
constructor(private firestore: AngularFirestore, private authService: AuthService) { }
/*
----------------------------------------------------
Transactions
----------------------------------------------------
*/
GetTransactions(intvl: Interval): Observable<QuerySnapshot<DocumentData>> {
return this.firestore.collection('transactions', ref => ref
.orderBy('date', 'asc')
.where("userId", "==", this.authService.userData.uid))
.get();
}
Комментарии:
1. Разве вы уже не делаете эквивалент в AngularFire путем реализации
this.afAuth.authState.subscribe
? Кроме того, я не вижу кода, который генерирует ошибку, которую вы приводите здесь. Возможно, вы делаете что-то не так.2. Для справки я добавил в сообщение, что вызывает Firebase и что выдает ошибку.
3. Я полагаю, что ваш код предполагает подписку на authState, чтобы получать объект user всякий раз, когда он впервые становится доступным. Похоже, что ваше использование
this.authService.userData
не будет ждать, пока будет выпущен первый пользовательский объект.4. Исправлено. Я реализовал onAuthStateChanged() в AuthGuard. Работает как шарм.