Angular 2 - Routing - CanActivate使用Observable

时间:2016-06-21 15:04:59

标签: angular angular2-routing angular2-http

我有一个实施 CanActivate AuthGuard (用于路由)。

canActivate() {
    return this.loginService.isLoggedIn();
}

我的问题是,CanActivate结果取决于http-get-result - LoginService 会返回 Observable

isLoggedIn():Observable<boolean> {
    return this.http.get(ApiResources.LOGON).map(response => response.ok);
}

我如何将这些结合在一起 - 使CanActivate依赖于后端状态?

8 个答案:

答案 0 :(得分:115)

您应该将“@ angular / router”升级到最新版本。例如“3.0.0-alpha.8”

修改AuthGuard.ts

#include <stdio.h>
#include <stdlib.h>

typedef struct line
{
   int x;
} *line;

int main()
{
    line *array = malloc(10 * sizeof(line));

    int i = 0;

    for(i; i < 2; i++)
    {
        // XXX HERE YOU ALLOCATE MORE MEMORY
        array[i] = malloc(sizeof array[i]);
        array[i]->x = 5;
    }
    // XXX RESET "i" TO ZERO
    for(i=0; i < 2; i++)
    {
        printf("%d\n", array[i]->x);
    }

    return 0;
}

如果您有任何疑问,请问我!

答案 1 :(得分:33)

更新Kery Hu对Angular 5和RxJS 5.5 where the catch operator is deprecated. You should now use the catchError operator in conjunction with pipelettable operators的回答。

import { Injectable } from '@angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { catchError, map} from 'rxjs/operators';
import { of } from 'rxjs/observable/of';

@Injectable()
export class AuthGuard implements CanActivate {

  constructor(private loginService: LoginService, private router: Router) { }

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean>  {
    return this.loginService.isLoggedIn().pipe(
      map(e => {
        if (e) {
          return true;
        } else {
          ...
        }
      }),
      catchError((err) => {
        this.router.navigate(['/login']);
        return of(false);
      })
    );
  }   

}

答案 2 :(得分:7)

canActivate()接受Observable<boolean>作为返回值。守卫将等待Observable解析并查看该值。如果'是',它将通过检查,否则(任何其他数据或抛出的错误)将拒绝该路由。

您可以使用.map运算符将Observable<Response>转换为Observable<boolean>,如下所示:

canActivate(){
    return this.http.login().map((res: Response)=>{
       if ( res.status === 200 ) return true;
       return false;
    });
}

答案 3 :(得分:2)

我是这样做的:

private void MainPanel_DragEnter(object sender, DragEventArgs e)
    {
        e.AcceptedOperation = DataPackageOperation.Copy;
        e.DragUIOverride.Caption = "drop to add image file to collection";
        e.DragUIOverride.IsCaptionVisible = true;
        e.DragUIOverride.IsContentVisible = true;
    }



private async void MainPanel_Drop(object sender, DragEventArgs e)
        {
            if (e.DataView.Contains(StandardDataFormats.StorageItems))
            {
                var items = await e.DataView.GetStorageItemsAsync();
                // etc.
            }

        }

正如您所看到的,我正在向userService.auth发送一个回退函数,如果http调用失败该怎么办。

在userService中我有:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
return this.userService.auth(() => this.router.navigate(['/user/sign-in']));}

答案 4 :(得分:1)

这可能对您有帮助

import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { Select } from '@ngxs/store';
import { Observable } from 'rxjs';
import { map, take } from 'rxjs/operators';
import { AuthState } from 'src/app/shared/state';

export const ROLE_SUPER = 'ROLE_SUPER';

@Injectable()
export class AdminGuard implements CanActivate {

 @Select(AuthState.userRole)
  private userRoles$: Observable<string[]>;

  constructor(private router: Router) {}

 /**
   * @description Checks the user role and navigate based on it
   */

 canActivate(): Observable<boolean> {
    return this.userRoles$.pipe(
      take(1),
      map(userRole => {
        console.log(userRole);
        if (!userRole) {
          return false;
        }
        if (userRole.indexOf(ROLE_SUPER) > -1) {
          return true;
        } else {
          this.router.navigate(['/login']);
        }
        return false;
      })
    );
  } // canActivate()
} // class

答案 5 :(得分:0)

它如何在不致电订阅的情况下为您服务? 对我来说,当我通过.net API调用它时,什么也没有返回。我必须像这样在我的身份验证保护服务上调用subscribe,然后才进行实际的API调用。 但是由于订阅是异步的,所以我的canActivate防护无法正常工作,用户可以进入页面。

AuthGauard service:

canActivate() { this.loginService.isLoggedIn()
      .subscribe(response => {
          if (!response) return false;})
return true;
}

loginService:
    isLoggedIn():Observable<boolean> {
        return this.http.get(ApiResources.LOGON).pipe(map(response => response.ok));
    }

答案 6 :(得分:-1)

CanActivate可以与Observable一起使用,但是当像CanActivate那样进行2次调用时失败:[Guard1,Guard2]。
这里,如果从Guard1返回一个Observable of false,那么它将检查Guard2并允许在Guard2返回true时访问路由。 为了避免这种情况,Guard1应该返回一个布尔值而不是布尔值的Observable。

答案 7 :(得分:-6)

在canActivate()中,您可以返回一个本地布尔属性(在您的情况下默认为false)。

private _canActivate: boolean = false;
canActivate() {
  return this._canActivate;
}

然后在LoginService的结果中,您可以修改该属性的值。

//...
this.loginService.login().subscribe(success => this._canActivate = true);