输入网址时canActivate无法正常工作

时间:2018-07-17 10:42:36

标签: angular authentication subscribe canactivate

基本上,一切正常,直到由于某种原因键入URL时,canActivate方法中的变量this.estado碰巧未定义。

我认为这是因为构造函数没有在正确的时间获得可观察到的结果。

import { Component, Injectable, Inject, OnInit } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';


@Injectable()
export class AuthService implements CanActivate {
  myAppUrl: string;
  estado: any;

  constructor(private router: Router, private http: HttpClient, @Inject('BASE_URL') private baseUrl: string) {
    this.myAppUrl = baseUrl;
    this.estadoSetUp(); /* If I put hear this.estado = true everything works fine */
  }

  public getJSON(): Observable<any> {
    return this.http.get(this.myAppUrl + 'api/IsAuthenticated');
  }

  public estadoSetUp() {
    this.getJSON().subscribe(data => {
      this.estado = data.AmILoggin;
    });
  }

  canActivate(): Observable<boolean> {
    if (this.estado != true) {
      this.router.navigate(['/']);
    }

    return this.estado;
  }
}

感谢@sirdieter

我将解决方案留给以后遇到任何麻烦的人:

import { Component, Injectable, Inject, OnInit } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot       } from '@angular/router';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { ReplaySubject } from 'rxjs/ReplaySubject'
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
import 'rxjs/add/operator/do';

@Injectable()
export class AuthService implements CanActivate {
  myAppUrl: string;
  private isAuthorized = new ReplaySubject<boolean>(1);

  constructor(private router: Router, private http: HttpClient,     @Inject('BASE_URL') private baseUrl: string) {
    this.myAppUrl = baseUrl;
    this.estadoSetUp();
  }

  public getJSON(): Observable<any> {
    return this.http.get(this.myAppUrl + 'api/IsAuthenticated');
  }

  public estadoSetUp() {
    this.getJSON().subscribe(data => {
      this.isAuthorized.next(data.AmILoggin);
    });
  }

  canActivate(): Observable<boolean> {
    return this.isAuthorized.asObservable()
      .do(auth => {
        if (auth != true) {
          this.router.navigate(['/']);
        }
      });
  }
}

2 个答案:

答案 0 :(得分:2)

请注意,您的http通话是异步的

因此,当您直接打开URL时,将构造此防护(它将启动http调用),并且在此之后不久(毫秒),将调用“ canActivate”。 结果,如果您的http调用速度不够快,则因为没有来自http调用的结果,所以未定义您的变量。

canActivate返回一个布尔值的Observable。因此,一种解决方案是将您的可变estado更改为可观察的

答案 1 :(得分:1)

您已正确找到问题所在。 您可以返回可观察到的http调用,并将其映射到AmILoggin属性。 (RxJS 6语法,您似乎有5个)

canActivate(): Observable<boolean> {
    return this.getJSON().pipe(pluck('AmILoggin');
}

但是在这种情况下,每次调用canActivate()时,您都要进行http调用; 要只打一个http电话,您可以使用主题:

private isAuthorized = new ReplaySubject<boolean>(1);

public estadoSetup() {
    this.getJSON().subscribe(data => this.isAuthorized.next(data.AmILoggin));
}
// RxJS 6
canActivate() {
    return this.isAuthorized.asObservable().pipe(
      tap(auth => {
        if (auth) {
            this.router.navigate(['/']);
        }
      }
    );
}
// RxJS 5
canActivate(): Observable<boolean>
    return this.isAuthorized.asObservable()
    .do(auth => {
        if (auth) {
            this.router.navigate(['/']);
        }
    });