【问题标题】:Angular 2 - Routing - CanActivate work with ObservableAngular 2 - 路由 - CanActivate 与 Observable 一起工作
【发布时间】:2016-10-23 05:12:35
【问题描述】:

我有一个实现 CanActivateAuthGuard(用于路由)。

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 年开始的 - 角度/路由器的早期阶段已经被使用。

######

【问题讨论】:

  • 你读过这里吗? angular.io/docs/ts/latest/guide/router.html 搜索 Route Guards 这是 CanActivate 的 api 参考:angular.io/docs/ts/latest/api/router/index/… 如您所见,它可以返回布尔值或 Observable
  • canActivate() 可以返回一个Observable,只要确保Observable 已经完成(即observer.complete())。
  • @PhilipBulley 如果 observable 发出更多值然后完成怎么办?守门员是做什么的?目前我看到的是使用take(1)Rx操作符来实现stream的completnes,如果忘记添加怎么办?

标签: angular angular2-routing angular2-http


【解决方案1】:

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

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

然后在LoginService的结果中,你可以修改那个属性的值。

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

【讨论】:

  • 你是个天才,先生。
【解决方案2】:

您应该将“@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);
            });
    }
}

如果你有任何问题,可以问我!

【讨论】:

  • 值得指出的是,这与 Promise 的工作方式非常相似。对于我的实现,假设isLoggedIn()Promise,您可以使用isLoggedIn().then((e) =&gt; { if (e) { return true; } }).catch(() =&gt; { return false; }); 希望这对未来的旅行者有所帮助!
  • 我必须添加import 'rxjs/add/observable/of';
  • 现在不是一个好的答案 IMO .. 它没有提供服务器端正在发生的事情的详细信息......它在 alpha 时已经过时了! ...它不遵循此最佳实践..angular.io/docs/ts/latest/guide/… ..请参阅下面的更新答案(希望一天以上)
  • canActivate 应该重新调整 Observable
  • 现在是import { Observable, of } from 'rxjs';
【解决方案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);
  });}

【讨论】:

  • 就 .map() 函数而言非常好的答案 - 非常非常好:) - 没有使用回退回调 - 相反,我订阅了 canActivate 方法中的 auth Observable - 非常感谢想法
【解决方案4】:

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

您可以使用.map 运算符将Observable&lt;Response&gt; 转换为Observable&lt;boolean&gt;,如下所示:

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

【讨论】:

  • catch 块怎么样?如果 401 正确,则调用 catch 块?
  • 在角度 4 中不起作用。它需要在某个地方定义一个泛型类型。
【解决方案5】:

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

【讨论】:

    【解决方案6】:

    更新 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);
          })
        );
      }   
      
    }
    

    【讨论】:

    • 在 isLoggedIn() 之后我还有 1 个 XHR 调用,并且 XHR 的结果用于第二个 XHR 调用。如何进行第二个将接受第一个结果的 ajax 调用?你给出的例子很简单,如果我也有另一个 ajax,你能告诉我如何使用 pipe()。
    • 对于 angular 10 也非常有用
    • 谢谢。你救了我的一天!对 Angular 11 有用。
    【解决方案7】:

    这可能对你有帮助

    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
    

    【讨论】:

      猜你喜欢
      • 2018-12-22
      • 1970-01-01
      • 2015-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多