Angular:AuthGuard中的浏览器刷新处理

时间:2018-11-14 06:32:17

标签: angular angularfire2 auth-guard

我一直在尝试在我的Web应用程序中正确实现AuthGuard。目前,当我在应用程序中导航时,它可以正常工作。但是当我刷新时,在AuthService完成执行之前,authService.loggedIn被处理为false。

这是我的代码:

auth.guard.ts



    import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot} from '@angular/router';
    import {Injectable} from '@angular/core';
    import {AuthService} from './auth.service';

    @Injectable()
    export class AuthGuard implements CanActivate {
      constructor(private authService: AuthService, private router: Router) {
      }

      canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
        if (state.url === '/login') {
          if (this.authService.loggedIn) {
            this.router.navigate(['/']).then().catch();
          } else {
            return true;
          }
        } else {
          if (this.authService.loggedIn) {
            return true;
          } else {
            this.router.navigate(['/login']).then().catch();
          }
        }
      }
    }

auth.service



    import {Injectable, OnInit} from '@angular/core';
    import {AngularFireAuth} from '@angular/fire/auth';
    import {auth} from 'firebase';
    import {Router} from '@angular/router';
    import {Subject} from 'rxjs';

    @Injectable({
      providedIn: 'root'
    })
    export class AuthService implements OnInit {
      loggedIn = false;

      constructor(public afAuth: AngularFireAuth, private router: Router) {
        this.afAuth.authState.subscribe((user) => {
          if (user) {
            this.loggedIn = true;
          }
        });
      }

      ngOnInit() {
      }

      ...
    }

我在线研究,他们提到了不同的方法 (例如https://gist.github.com/codediodeio/3e28887e5d1ab50755a32c1540cfd121),但无法在我的应用程式上运作。

尝试这种方法时遇到的一个错误是“ src / app / auth.guard.ts(20,8)中的错误:错误TS2339:类型“可观察”的属性“ take”不存在。”我用

import {AngularFireAuth} from '@angular/fire/auth';

不是

import { AngularFireAuth } from 'angularfire2/auth';

任何帮助/建议都值得赞赏。

谢谢大家。

2 个答案:

答案 0 :(得分:0)

我能够通过浏览器刷新使AuthGuard工作。

此链接有很大帮助:https://gist.github.com/codediodeio/3e28887e5d1ab50755a32c1540cfd121

由于我使用的是rxjs的较新版本,因此我仅使用pipe()来链接运算符,并使用tap()而不是do()。

代码如下:



    ...
    import {Observable} from 'rxjs';

    import {take, map, tap} from 'rxjs/operators';

    @Injectable()
    export class AuthGuard implements CanActivate {
      constructor(private router: Router, private afAuth: AngularFireAuth) {
      }

      canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable {
        return this.afAuth.authState
          .pipe(
            take(1),
            map(user => !!user),
            tap(
              loggedIn => {
                if (!loggedIn) {
                  this.router.navigate(['/login']);
                }
              }
            )
          );
      }
    }

谢谢。

答案 1 :(得分:0)

您可以通过执行以下提到的步骤来实现:

1)首先在authService中,创建用户EX的行为主题:

user = new BehaviorSubject<any>(null); 

2)现在在authService中创建登录功能

logIn(email: string, password: string) {
  // do some logging in functionality over here 
  // like authenticating the user, then emit the userInfo 
  // and save it to the storage.
  this.user.next(userData);
  localStorage.setItem('userData', userData);
  // also, now here after logging in navigate to your next url which is protected from guard or other some other url.
}

3)现在创建一个自动登录功能

autoLogin() {
 const userData = localStorage.getItem('userData');
 if (!userData) {
    this.user.next(null);
    return;
 }
 this.user.next(userData);
}

4)现在在auth.guard.ts中编写以下代码

import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot, Router } from '@angular/router';
import { AuthService } from './auth.service';
import { map, take } from 'rxjs/operators';


@Injectable({providedIn: 'root'})
export class AuthGuard implements CanActivate {
    constructor(private authService: AuthService, private router: Router) { }

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
        this.authService.autoLogin();
        return this.authService.user.pipe(take(1), map(user => {
            const isAuth = !!user;
            if (isAuth) {
                return true;
            } else {
                return this.router.createUrlTree(['/auth']);
            }
        }));
    }
}

5)不要忘记在您想要应用防护的路由配置中添加canActivate对象

例如

{ path : 'root', component: SuperadminComponent, canActivate: [AuthGuard] }

注释1 :如果AuthGuard中未提供{providedIn:'root'},则不要忘记将其添加到app.module.ts的provider数组或任何模块中您要使用的地方

注释2 :在注销时清除存储,并将用户释放为空。

希望这对您或其他人有帮助!