使用Firebase身份验证和Ngrx进行路由防护

时间:2018-08-31 09:25:58

标签: firebase redux firebase-authentication angular-routing ngrx

使用Ngrx存储正确验证身份验证状态

当我访问应用程序的某些路由时,需要通过检查商店的用户身份验证状态来验证用户是否已通过身份验证。

当我访问路由并调用CanActivate()方法时,我已经验证了身份验证状态是初始状态集,如果需要,我需要使用已身份验证的用户更改身份验证状态。

CanActivate()方法中,我尝试调用GetUser()操作,然后进行选择以检查用户是否已通过身份验证,但这不能正常工作。

下面是我执行验证的代码。

我的应用程序使用 Firebase身份验证服务,因此我的身份验证服务中有一个方法可以返回用户的身份验证状态。

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

0 个答案:

没有答案