angular - 在 Angular 4 的 canactivate guard 中返回 observable inside observable

标签 angular typescript angular-ui-router observable

所以我必须在路由器的 canActivate 守卫中做两件事。首先,我必须检查用户是否获得授权,我通过调用 OpenIdcSecutiry 服务来执行此操作,然后如果用户获得授权,我必须通过调用另一个返回 UserProfile 的服务(包括其 Angular 色)来检查用户 Angular 色。我知道我可以返回一个 Observable,事实上如果我这样做:

return this.oidcSecurityService.getIsAuthorized();

它有效,但显然我没有检查用户 Angular 色。现在我有这个:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {

return this.oidcSecurityService.getIsAuthorized()
  .map(
    data => {
      if (data === false) {
        this.router.navigate(['/login']);
        return data;
      }
      if (data === true) {
        const roles = route.data['roles'] as Array<string>;
        if (roles) {
        this.profileService.getObservableUserProfileFromServer().map(userProfile => {
          const userRoles = userProfile.Roles;
          for (const role of roles) {
            if (userRoles.indexOf(role) > -1) {
              return true;
            }
          }
          return false;
        });
        }
        return data;
      }
    },
    error => {
      this.router.navigate(['/login']);
      return error;
    }
  );

this.profileService.getObservableUserProfileFromServer() 从未被调用,我不知道如何在知道用户获得授权后检查用户 Angular 色。我怎样才能做到这一点?我可以在我的 Observable 中返回 Observable 吗?

EDIT1:我将代码更改为:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {

return this.oidcSecurityService.getIsAuthorized()
  .map(
    data => {
      if (data === false) {
        this.router.navigate(['/login']);
        return data;
      }
      if (data === true) {
        const roles = route.data['roles'] as Array<string>;
        if (roles) {
          return this.profileService.getObservableUserProfileFromServer().toPromise().then(userProfile => {
              const userRoles = userProfile.Roles;
              for (const role of roles) {
                if (userRoles.indexOf(role) > -1) {
                  return true;
                }
              }
              return false;
          }
            );
        }
        return data;
      }
    },
    error => {
      this.router.navigate(['/login']);
      return error;
    }
  );

//返回 this.oidcSecurityService.getIsAuthorized();

现在我可以看到如何调用 this.profileService.getObservableUserProfileFromServer 并从服务器接收结果,但结果未在 canActivate 守卫中评估,它只是忽略结果并表示导航已取消。

编辑决赛:

@llai 给了我答案,必须使用两个 switchmap 来链接多个 observable,最终代码在这里:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {

return this.oidcSecurityService.getIsAuthorized()
  .switchMap(
    data => {
      if (data === false) {
        this.router.navigate(['/login']);
        return Observable.of(false); // user not logged in, canActivate = false
      } else if (data === true) {
        const roles = route.data['roles'] as Array<string>;
        if (roles) {
          // return inner observable
          return this.profileService.getObservableUserProfileFromServer()
            .switchMap(userProfile => {
              const userRoles = userProfile.Roles;
              for (const role of roles) {
                if (userRoles.indexOf(role) > -1) {
                  // role found, canActivate = true
                  return Observable.of(true);
                }
              }
              // no matching role, canActivate = false
              return Observable.of(false);
            });
        } else {
          // no roles defined in route data, canActivate = false
          return Observable.of(true);
        }
      }
    });

最佳答案

正如 Christian 在评论中提到的,您应该使用 switchMap 将您的可观察对象链接在一起。

在您的第一个实现中,您没有返回内部可观察对象,因此路由器从不订阅它,所以它永远不会被调用。

在您的第二个实现中,您正在“订阅”(转换为 promise + then)到 map 函数中的可观察对象,这会触发内部可观察对象。然而,由于 observable 没有返回给守卫,守卫不会等待内部 observable 完成。


相反,您应该链接可观察对象并将链接的序列返回给守卫。这将允许守卫订阅序列并等待正确的响应。

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {

    return this.oidcSecurityService.getIsAuthorized()
      .switchMap(
        data => {
          if (data === false) {
            this.router.navigate(['/login']);
            return Observable.of(false); // user not logged in, canActivate = false
          }else if (data === true) {
            const roles = route.data['roles'] as Array<string>;
            if (roles) {
              // return inner observable
              return this.profileService.getObservableUserProfileFromServer()
                .map(userProfile => {
                  const userRoles = userProfile.Roles;
                  for (const role of roles) {
                    if (userRoles.indexOf(role) > -1) {
                      // role found, canActivate = true
                      return true;
                    }
                  }
                  // no matching role, canActivate = false
                  return false;
                });
            }else{
              // no roles defined in route data, canActivate = false
              return Observable.of(false)
            }
          }
        }
      }
    );

}

关于angular - 在 Angular 4 的 canactivate guard 中返回 observable inside observable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47291893/

相关文章:

Angular 2 : EXCEPTION: Response with status: 0 for URL: null

javascript - Angular2 - 将表导出到 html excel 并给出文件名

javascript - 意外的标记 { 语法错误

javascript - jQuery scrollTop() 为所有元素返回 0

javascript - Angularjs 不呈现 $rootscope 数据

asynchronous - Angular2 异步数据问题

angular - 如何根据某人是否使用移动设备更改我的 Angular 组件 HTML?

angular - 仅针对第一个事件触发 combineLatest

javascript - 可以预加载使用 canLoad 的模块吗?

javascript - Angular 2 一个组件中的多条路线