Angular7 AuthGuard Firebase声明

时间:2019-03-22 15:53:38

标签: angular firebase asynchronous auth-guard

我可以使用Firebase登录,但是在我的应用程序中,我有3个级别的用户。我们称他们为admin,用户,编辑者。我将用户角色保留在Firebase提供的自定义声明中。

在AuthGuard中,我传递数据expectedRoles = ['admin', 'editor'],并添加我想允许用于特定路由的角色。而且我想重定向到自己的页面,例如编辑器尝试将管理路由返回到编辑器仪表板。

这是我的AuthGuard的canActivate函数:

return this.auth.user.pipe(
  map(user => {
    if (user) {
      user.getIdTokenResult().then((idTokenResult) => {
        if (idTokenResult.claims.admin) {
          if (expectedRoles.indexOf('admin') > -1) {
            return true;
          } else {
            // return back to admin dashboard
            this.router.navigate(['/admin']);
          }
        } else if (idTokenResult.claims.editor) {
          if (expectedRoles.indexOf('editor') > -1) {
            return true;
          } else {
            // return back to editor dashboard
            this.router.navigate(['/editor']);
          }
        } else if (idTokenResult.claims.user) {
          if (expectedRoles.indexOf('user') > -1) {
            return true;
          } else {
            // return back to user dashboard
            this.router.navigate(['/user']);
          }
        } else {
          // Unexpected claim, better logout, TODO; display something
          this.router.navigate(['/auth/logout']);
        }
      });
    } else {
      // User is not authenticated
      // Check if we are expecting a guest
      if (expectedRoles.indexOf('guest') > -1) {
        return true;
      } else {
        this.router.navigate(['/auth/login']);
      }
    }
  })
).first();

在添加user.getIdTokenResult().then(...)之前,它工作正常,我知道这可能是由于不等待异步调用来解析自定义声明。我该如何解决?

2 个答案:

答案 0 :(得分:2)

使用switchMap代替map,创建函数async并等待结果。 switchMap接受async函数返回的承诺。然后,您可以在内部使用await

return this.auth.user.pipe(
  // switchMap instead of map
  // async function call
  switchMap(async (user) => {
    if (user) {
      // await here
      await user.getIdTokenResult().then((idTokenResult) => {
        if (idTokenResult.claims.admin) {
          if (expectedRoles.indexOf('admin') > -1) {
            return true;
          } else {
            // return back to admin dashboard
            this.router.navigate(['/admin']);
          }
        } else if (idTokenResult.claims.editor) {
          if (expectedRoles.indexOf('editor') > -1) {
            return true;
          } else {
            // return back to editor dashboard
            this.router.navigate(['/editor']);
          }
        } else if (idTokenResult.claims.user) {
          if (expectedRoles.indexOf('user') > -1) {
            return true;
          } else {
            // return back to user dashboard
            this.router.navigate(['/user']);
          }
        } else {
          // Unexpected claim, better logout, TODO; display something
          this.router.navigate(['/auth/logout']);
        }
      });
    } else {
      // User is not authenticated
      // Check if we are expecting a guest
      if (expectedRoles.indexOf('guest') > -1) {
        return true;
      } else {
        this.router.navigate(['/auth/login']);
      }
    }
  })
).first();

只是与该解决方案无关的提示-比在AuthGuard函数中加载令牌声明更好,您应该在用户登录后加载它并将其存储在商店中,就像使用登录响应中的信息存储方式一样。这样会更快。

答案 1 :(得分:0)

尝试对内部可观察的调用使用rxjs管道:flatMap和flatMapTo或mergeMap或mergeMapTo。在您的特定情况下,我认为可以使用mergeMap。

随时阅读rxjs中的那些管道,它们可能是解决方案