【问题标题】:canActivate not working when url is typed输入 url 时 canActivate 不起作用
【发布时间】:2018-07-18 16:39:53
【问题描述】:

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

我认为这是因为构造函数没有在正确的时间得到 observable。

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(['/']);
        }
      });
  }
}

【问题讨论】:

    标签: angular authentication subscribe canactivate


    【解决方案1】:

    请注意,您的 http 调用是异步的,

    因此,当您直接打开一个 URL 时,会构造这个守卫(它会启动 http 调用),然后很快(毫秒)就会调用“canActivate”。 因此,如果您的 http 调用不够快,则您的变量没有定义,因为 http 调用没有结果。

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

    【讨论】:

    • 是的,我已经尝试过了,但是我怎样才能将 this.estado 与 true 进行比较?我是 Angular 新手,我很迷茫……
    【解决方案2】:

    您正确地发现了问题。 您可以返回 http 调用 observable 并将其映射到 AmILoggin 属性。 (RxJS 6 Syntax,你好像有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(['/']);
            }
        });
    

    【讨论】:

    • 您的代码似乎对我有用,但有什么方法可以比较 this.isAuthorized.asObservable();是真还是假?
    • 你可以使用 tap (RxJS 6)/ do (RxJS 5) 操作符。检查我的编辑。
    • 我无法管理您的第二个代码工作,它让我在 canActivate 上出错。我做了一个临时解决方案。使用您的第一个代码。这有点疯狂,因为它为这么简单的事情提出了大量的请愿书,但至少现在有效:(this.estado = this.getJSON().pipe(pluck('AmILoggin')); this.estado.subscribe(val =&gt; { if (val == false) { this.router.navigate(['/']) } }); return this.estado;
    • 你使用什么版本的 Angular?
    • 我们使用 angular 5,因为它是 asp.net core 2 附带的最后一个模板,没有任何技巧,或者至少他们是这么告诉我的。
    猜你喜欢
    • 2016-05-03
    • 1970-01-01
    • 1970-01-01
    • 2017-03-13
    • 2011-04-01
    • 2018-08-16
    • 2021-09-11
    • 2012-07-12
    • 1970-01-01
    相关资源
    最近更新 更多