typescript - Angular2 canActivate() kutsuu asynkronista funktiota


Yritän käyttää Angular2-reitittäjän suojauksia rajoittaakseni pääsyä joihinkin sovellukseni sivuihin. Käytän Firebase Authenticationia. Tarkistaakseni, onko käyttäjä kirjautunut Firebaseen, minun täytyy kutsua .subscribe() FirebaseAuth-objektissa takaisinsoittomenetelmällä. Tämä on suojauksen koodi:

import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { AngularFireAuth } from "angularfire2/angularfire2";
import { Injectable } from "@angular/core";
import { Observable } from "rxjs/Rx";

@Injectable()
export class AuthGuard implements CanActivate {

    constructor(private auth: AngularFireAuth, private router: Router) {}

    canActivate(route:ActivatedRouteSnapshot, state:RouterStateSnapshot):Observable<boolean>|boolean {
        this.auth.subscribe((auth) => {
            if (auth) {
                console.log('authenticated');
                return true;
            }
            console.log('not authenticated');
            this.router.navigateByUrl('/login');
            return false;
        });
    }
}

Kun siirryn sivulle, jolla on suoja, konsoliin tulostuu joko authenticated tai not authenticated (jonkin viiveen jälkeen, kun odotetaan vastausta Firebaselta). Kuitenkin siirtyminen ei koskaan toteudu. Lisäksi, jos en ole kirjautunut sisään, minut ohjataan /login reitille. Joten ongelma, jota minulla on, on se, että return true ei näytä pyydettyä sivua käyttäjälle. Oletan, että tämä johtuu siitä, että käytän callbackia, mutta en pysty keksimään, miten tehdä se muuten. Mitä ajatuksia?

Vastaus #1

canActivate tarvitsee palauttaa Observable, joka suoritetaan loppuun:

@Injectable()
export class AuthGuard implements CanActivate {

    constructor(private auth: AngularFireAuth, private router: Router) {}

    canActivate(route:ActivatedRouteSnapshot, state:RouterStateSnapshot):Observable<boolean>|boolean {
        return this.auth.map((auth) => {
            if (auth) {
                console.log('authenticated');
                return true;
            }
            console.log('not authenticated');
            this.router.navigateByUrl('/login');
            return false;
        }).first(); // this might not be necessary - ensure `first` is imported if you use it
    }
}

Puuttuu return ja käytän map() subscribe() sijaan, koska subscribe() palauttaa Subscription, ei Observable

Vastaus #2

Voit käyttää Observable-luokkaa asynkronisen logiikan osan käsittelemiseen. Tässä on koodi, jota testaan esimerkkinä:

import { Injectable } from '@angular/core';
import { CanActivate } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { DetailService } from './detail.service';

@Injectable()
export class DetailGuard implements CanActivate {

  constructor(
    private detailService: DetailService
  ) {}

  public canActivate(): boolean|Observable<boolean> {
    if (this.detailService.tempData) {
      return true;
    } else {
      console.log('loading...');
      return new Observable<boolean>((observer) => {
        setTimeout(() => {
          console.log('done!');
          this.detailService.tempData = [1, 2, 3];
          observer.next(true);
          observer.complete();
        }, 1000 * 5);
      });
    }
  }
}

Vastaus #3

canActivate voi palauttaa myös Promise, joka ratkaisee boolean-arvon

Vastaus #4

Voit palauttaa true|false lupauksena.

import {Injectable} from '@angular/core';
import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot} from '@angular/router';
import {Observable} from 'rxjs';
import {AuthService} from "../services/authorization.service";

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

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
  return new Promise((resolve, reject) => {
  this.authService.getAccessRights().then((response) => {
    let result = <any>response;
    let url = state.url.substr(1,state.url.length);
    if(url == 'getDepartment'){
      if(result.getDepartment){
        resolve(true);
      } else {
        this.router.navigate(['login']);
        resolve(false);
      }
    }

     })
   })
  }
}

Aiheeseen liittyviä artikkeleita