Корректная проверка статуса аутентификации с использованием хранилища Ngrx
Мне нужно проверить, аутентифицирован ли пользователь, когда я получаю доступ к какому-либо маршруту моего приложения, проверив хранилище на предмет состояния аутентификации пользователя.
Когда я получаю доступ к маршруту и вызывается метод CanActivate()
, я проверил, что состояние аутентификации является начальным набором состояний, мне нужно, чтобы статус аутентификации был изменен для аутентифицированного пользователя, если он есть.
В методе CanActivate()
я пытался вызвать действие GetUser()
перед выполнением выбора, проверяя, аутентифицирован ли пользователь или нет, но это не работает должным образом.
Ниже приведен код выполнения проверки.
Мое приложение использует службу Firebase Authentication , поэтому в моей службе аутентификации есть метод, который возвращает состояние аутентификации пользователя.
getUsuario(): Observable<firebase.User> {
return this._angularFireAuth.authState;
}
auth.state.ts:
import { createFeatureSelector, createSelector } from '@ngrx/store';
import * as fromAuth from '../reducers/auth.reducer';
export interface AuthState {
userData: any; // firebase user models
isLoggedIn: boolean;
error: any;
loading?: boolean;
loaded: boolean;
}
export const authInitialState: AuthState = {
userData: null,
isLoggedIn: false,
error: null,
loaded: false,
};
export const getAuthState = createFeatureSelector<AuthState>('auth');
export const getAuthUserData = createSelector(getAuthState, fromAuth.getUserData);
export const getAuthIsLoggedIn = createSelector(getAuthState, fromAuth.getIsUserLoggedIn);
export const getAuthError = createSelector(getAuthState, fromAuth.getError);
auth.reducer.ts:
import { AuthActions, ActionsTypes } from '../actions/auth.actions';
import { AuthState, authInitialState } from '../states/auth.state';
export function reducer(
state = authInitialState, action: AuthActions): AuthState {
switch (action.type) {
case ActionsTypes.GET_USER: {
return {
...state,
loaded: false,
loading: true
};
}
case ActionsTypes.AUTHENTICATED:
return {
...state,
userData: action.payload,
loaded: true,
loading: false,
isLoggedIn: true
};
case ActionsTypes.NOT_AUTHENTICATED:
return {
...state,
...authInitialState,
loaded: true,
loading: false,
isLoggedIn: false
};
case ActionsTypes.LOGIN_EMAIL_PASSWORD:
return {
...state,
loading: true
};
case ActionsTypes.AUTH_ERROR:
return {
...state,
...action.payload,
loading: false
};
case ActionsTypes.LOGOUT:
return {
...state,
loading: true
};
default: {
return state;
}
}
}
export const getUserData = (state: AuthState) => state.userData;
export const getIsUserLoggedIn = (state: AuthState) => state.isLoggedIn;
export const getError = (state: AuthState) => state.error;
auth.effects.ts:
import { Injectable } from '@angular/core';
// Services
import { AuthService } from '../services/auth.service';
// RxJS
import { Observable } from 'rxjs/Observable';
import { map, switchMap, catchError } from 'rxjs/operators';
import { of } from 'rxjs/observable/of';
// NGRX
import { Action } from '@ngrx/store';
import { Actions, Effect } from '@ngrx/effects';
import * as authActions from '../actions/auth.actions';
import { Router } from '@angular/router';
@Injectable()
export class AuthEffects {
constructor(
private _router: Router,
private _authService: AuthService,
private _actions$: Actions,
) { }
@Effect()
getUser: Observable<Action> = this._actions$.ofType(authActions.ActionsTypes
.GET_USER).pipe(
map((action: authActions.GetUser) => action.payload),
switchMap(() => this._authService.getUsuario()),
map(user => {
if (user) {
const usuario = {
uid: user.uid,
email: user.email,
displayName: user.displayName
};
return new authActions.Authenticated(usuario);
} else {
this._router.navigate(['auth/login']);
return new authActions.NotAuthenticated();
}
})
);
@Effect()
loginEmailPassword: Observable<Action> = this._actions$.ofType(authActions.ActionsTypes
.LOGIN_EMAIL_PASSWORD).pipe(
map((action: authActions.LoginEmailPassword) => action.payload),
switchMap(usuario => this._authService
.loginWithEmailAndPassword(usuario.email, usuario.password).pipe(
map(() => {
this._router.navigate(['']);
return new authActions.GetUser();
}),
catchError((err => of(new authActions.AuthError({ error: err }))))
))
);
@Effect()
logout: Observable<Action> = this._actions$.ofType(authActions.ActionsTypes
.LOGOUT).pipe(
map((action: authActions.Logout) => action.payload),
switchMap(() => this._authService.logout().pipe(
map(() => {
this._router.navigate(['auth/login']);
return new authActions.NotAuthenticated();
}),
catchError((err => of(new authActions.AuthError({ error: err }))))
))
);
@Effect()
reautenticaUsuario: Observable<Action> = this._actions$.ofType(authActions.ActionsTypes
.REAUTHENTICATE).pipe(
map((action: authActions.Reauthenticate) => action.payload.password),
switchMap(password => this._authService
.reauthenticateUsuario(password).pipe(
map(() => new authActions.ReauthenticateSuccess()),
catchError((err => of(new authActions.AuthError({ error: err }))))
))
);
}
auth.guard.ts:
canActivate(): Observable<boolean> {
this._store.dispatch(new fromAuth.GetUser());
return this._store.select(getAuthIsLoggedIn);
}