Вы должны изменить свой IsLoggedGuard следующим образом:
@Injectable()
export class IsLoggedGuard implements CanActivate {
constructor(private auth: AuthService, private router: Router) { }
canActivate() {
return this.auth.user
.take(1)
.map(authState => {
if (authState) {
//user is already loggedin
//route the user to Dashboard page
//Or a page where you want the app to naviagte
this.router.navigate("dashboard route");
//dont show the Login page
return false;
} else {
//user is not loggedin
return true;
}
});
}
}
Вы видели проблему, потому что, когда вы вводите URL "localhost: 4200 / # / auth" в браузере, тогда ваш AuthGuard.user.subscribe
[т.е. в конструкторе this.user.subscribe(
], возможно, еще не выдало никакого значения, когда IsLoggedGuard's canActivate()
выполнено [т.е. AuthService.isLoggedIn () может возвращать false
, поскольку обратный вызов подписки мог не выполняться (что заполняет userDetails)].
Дайте мне знать, если это решит вашу проблему.
Может быть лучший способ реализовать ваш AuthService, а также Guards для использования AuthService. Дайте мне знать, если вы хотите лучший код.
РЕДАКТИРОВАТЬ - Другой подход к написанию AuthService
Давайте изменим AuthService следующим образом:
export class AuthService {
//NOTE: I AM JUST SHOWING TWO THINGS - isUserLoggedIn AND userDetails
//FROM THIS CODE YOU WILL GET AN IDEA HOW TO WRITE OTHER PROPERTIES WHICH ARE RELEVANT FOR YOUR APP
//This will be used as a source for various observables
private _authState$: Observable<any>;
//Have an observable which will tell if user is loggedin or not
isUserLoggedIn$: Observable<boolean>;
userDetails$: Observable<firebase.User>;
public userProfileRef: firebase.database.Reference;
constructor(private _firebaseAuth: AngularFireAuth, private router: Router) {
this.userProfileRef = firebase.database().ref('/userProfile');
this.setupObserables();
}
setupObserables() {
// this observable will broadcast the emited values to multiple subscribers [or composed/dependent observables]
this._authState$ = this._firebaseAuth.authState
.publishReplay(1)
.refCount();
// lets componse/derive different observables required by the consumer of this service
// This observable's emitted value will tell if user is logged in or not
this.isUserLoggedIn$ = this._authState$
.map(user => {
return user ? true : false;
});
// This observable's emited value will return the user's detail [NOTE If user is not logged in then the emitted value will be NULL
// i.e. userDetail is NULL; Your consumer of this observable should decide what to do with NULL/NOT NULL Value]
this.userDetails$ = this._authState$
.map(user => user);
}
doSignOut() {
this._firebaseAuth.auth.signOut()
.then((res) => this.router.navigate(['/auth/login']));
}
}
Теперь давайте воспользуемся обновленным AuthService в IsLoggedGuard:
@Injectable()
export class IsLoggedGuard implements CanActivate {
constructor(private auth: AuthService, private router: Router) { }
canActivate() {
return this.auth.isUserLoggedIn$
.take(1)
.map(isLoggedIn => {
if (isLoggedIn) {
//user is already loggedin
//route the user to Dashboard page
//Or a page where you want the app to naviagte
this.router.navigate("dashboard route");
//dont show the Login page
return false;
} else {
//user is not loggedin
return true;
}
});
}
}
Теперь давайте воспользуемся обновленным AuthService в AuthGuard:
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private auth: AuthService, private router: Router) { }
canActivate() {
return this.auth.isUserLoggedIn$
.take(1)
.map(isLoggedIn => {
if (!isLoggedIn) {
//user isNOT loggedin
//route the user to login page
this.router.navigate(['auth/sigin']);
//dont show the next route
//lets fail the guard
return false;
} else {
//user is loggedin; pass the guard i.e. show the next route associated with this guard
return true;
}
});
}
}
Теперь предположим, что какой-то компонент (предположим, имя компонента UserComponent
), вы хотите показать подробности пользователя, зарегистрированного в системе:
....component decorator...
export class UserComponent implements OnInit {
userDetails$: Observable<User>;
constructor(private _authService: AuthService) {
this.userDetails$ = this._authService.userDetails$;
}
}
Отобразить пользовательские детали, как это:
<div *ngIf="(userDetails$ | async) as userDetails">
<!-- Render your user details here -->
<!-- If userDetails is NULL then nothing will be rendered -->
</div>
ВНИМАНИЕ - В этом обновленном коде НИГДЕ мы подписываемся на любую из наблюдаемых. Обратите внимание, async
в шаблоне компонента, это заботится о подписке / отмене подписки на используемые наблюдаемые.
Надеюсь, это даст вам направление / идею. Давайте будем как можно более "Реактивными" вместо "Императивов" .. :) 1039 *
ПРИМЕЧАНИЕ: Я протестировал эквивалентный код в rxjs6. Похоже, вы используете rxjs5, поэтому я настроил опубликованный код в соответствии с rxjs5. Надеюсь, это сработает.