103

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

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

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

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

我怎样才能将它们组合在一起 - 使 CanActivate 依赖于后端状态?

######

编辑:请注意,这个问题来自 2016 年 - 角度/路由器的早期阶段已经被使用。

######

4

7 回答 7

157

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

修改 AuthGuard.ts

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

    canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
        return this.loginService
            .isLoggedIn()
            .map((e) => {
                if (e) {
                    return true;
                }
            })
            .catch(() => {
                this.router.navigate(['/login']);
                return Observable.of(false);
            });
    }
}

有什么问题可以问我!</p>

于 2016-06-27T01:15:33.000 回答
74

更新 Kery Hu 对 Angular 5+ 和 RxJS 5.5 的回答,其中catch不推荐使用运算符。您现在应该将 catchError 运算符与 pipelettable运算符结合使用。

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);
      })
    );
  }   
  
}
于 2018-05-02T21:21:24.673 回答
12

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;
    });
}
于 2017-01-23T10:59:09.743 回答
3

我是这样做的:

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

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

在 userService 我有:

import 'rxjs/add/observable/of';

auth(fallback): Observable<boolean> {
return this.http.get(environment.API_URL + '/user/profile', { withCredentials: true })
  .map(() => true).catch(() => {
    fallback();
    return Observable.of(false);
  });}
于 2016-12-22T15:26:58.117 回答
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
于 2019-01-31T05:47:51.730 回答
-1

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

于 2017-08-01T17:05:40.623 回答
-10

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

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

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

//...
this.loginService.login().subscribe(success => this._canActivate = true);
于 2016-06-22T04:33:15.860 回答