0

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

在 AuthGuard 中,我传递 data 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(...)它工作正常,我知道这可能是由于没有等待异步调用来解析自定义声明。我该如何解决这个问题?

4

2 回答 2

2

使用switchMap而不是地图,制作函数async并等待结果。switchMap接受async函数返回的承诺。然后在里面你可以 user 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 函数中加载令牌声明更好,您应该在用户登录后加载它并将其存储在存储中,就像存储登录响应中的信息一样。这会快得多。

于 2019-03-22T15:56:46.347 回答
0

尝试使用 rxjs 管道进行内部 observable 调用:flatMap 和 flatMapTo 或 mergeMap 或 mergeMapTo。在您的具体情况下,我认为 mergeMap 是要走的路。

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

于 2019-03-22T15:58:45.170 回答