我可以使用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(...)
之前,它工作正常,我知道这可能是由于不等待异步调用来解析自定义声明。我该如何解决?
答案 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中的那些管道,它们可能是解决方案