简体   繁体   中英

Angular canActivate redirecting to login on browser refresh Firebase

Angular 5 authentication app using angularfire2 and firebase. The app works fine navigating using in-app links. However, if I hit the browser refresh, it redirects me back to the Login page. The allowed is always returning False even when is true because I made a successful Login with firebase.

AuthInfo

export class AuthInfo {  
    constructor(public $uid: string) {}

    isLoggedIn() {
        // console.log(this.$uid);
        return !!this.$uid;
    }
}

AuthService

import { Injectable } from '@angular/core';
// tslint:disable-next-line:import-blacklist
import {Observable, Subject, BehaviorSubject} from 'rxjs/Rx';
import {AngularFireAuth } from 'angularfire2/auth';
import { AuthInfo } from '../security/auth-info' ;
import {Router} from '@angular/router';
import * as firebase from 'firebase/app';

@Injectable()
export class AuthService {
  static UNKNOWN_USER = new AuthInfo(null);
  authInfo$: BehaviorSubject<AuthInfo> = new BehaviorSubject<AuthInfo>(AuthService.UNKNOWN_USER);

  constructor(private afAuth: AngularFireAuth, private router: Router) {}
    login(email, password): Observable<AuthInfo> {
        return this.fromFirebaseAuthPromise(this.afAuth.auth.signInWithEmailAndPassword(email, password));
    }

    // signUp(email, password) {
    //  return this.fromFirebaseAuthPromise(this.afAuth.auth.createUserWithEmailAndPassword(email, password));
    // }

    fromFirebaseAuthPromise(promise): Observable<any> {
        const subject = new Subject<any>();
        promise
              .then(res => {
                    const authInfo = new AuthInfo(this.afAuth.auth.currentUser.uid);
                    this.authInfo$.next(authInfo);
                    subject.next(res);
                    subject.complete();
                    // console.log(res);
                },
                err => {
                    this.authInfo$.error(err);
                    subject.error(err);
                    subject.complete();
                });
        return subject.asObservable();
    }

    logout() {
        this.afAuth.auth.signOut();
        this.authInfo$.next(AuthService.UNKNOWN_USER);
        this.router.navigate(['/login']);
    }
    refresh() {
        const url = window.location.href;
    } 
}

AuthGuard

import {tap, take, map} from 'rxjs/operators';
import {CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router} from '@angular/router';
// tslint:disable-next-line:import-blacklist
import {Observable} from 'rxjs/Rx';
import {Injectable} from '@angular/core';
import {AuthService} from '../security/auth-service';
import { Location } from '@angular/common';
import { auth } from 'firebase';
import { log } from '@firebase/database/dist/src/core/util/util';

@Injectable()
export class AuthGuard implements CanActivate {
    redirectUrl: string;
    currentURL= '';
    constructor(private authService: AuthService, private router: Router) {}

    canActivate(route: ActivatedRouteSnapshot,
                state: RouterStateSnapshot): Observable<boolean> {

        // tslint:disable-next-line:no-unused-expression
        console.log(this.authService.authInfo$);

        return this.authService.authInfo$.pipe(
            map(authInfo => authInfo.isLoggedIn()),
            take(1),
            tap(allowed => {
                if  (!allowed) {
                    console.log(allowed);
                     this.router.navigate(['/login']);
                }
            }),
        );
    }
}

The authInfo$ is initialised with UNKNOWN_USER which will always make the first fired value not true, when reloading you take only the first value take(1) which is the default.

One solution is making the first value null and filter null values in the Observable used in the guard :

AuthService

...
new BehaviorSubject<AuthInfo>(null);
...

AuthGuard

...
return this.authService.authInfo$.pipe(
  filter(_ => _ !== null),
  map(authInfo => authInfo.isLoggedIn()),
  take(1),
...

This way only values that have meaning for the guard would be fired.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM