Angular7 AuthGuard Firebase 声明
Angular7 AuthGuard Firebase Claims
我可以使用 firebase 登录,但是在我的应用程序中我有 3 个级别的用户。我们称他们为管理员、用户、编辑。我在 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(...)
之前它工作正常,我知道这可能是由于没有等待异步调用来解析自定义声明。我该如何解决这个问题?
使用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 函数中加载令牌声明更好,您应该在用户登录后加载它并以与存储信息相同的方式将其存储在商店中从登录响应。这样会快很多。
尝试使用 rxjs 管道进行内部可观察调用:flatMap 和 flatMapTo 或 mergeMap 或 mergeMapTo。在您的具体情况下,我认为 mergeMap 是可行的方法。
随意阅读 rxjs 中的那些管道,它们可能是解决方案
我可以使用 firebase 登录,但是在我的应用程序中我有 3 个级别的用户。我们称他们为管理员、用户、编辑。我在 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(...)
之前它工作正常,我知道这可能是由于没有等待异步调用来解析自定义声明。我该如何解决这个问题?
使用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 函数中加载令牌声明更好,您应该在用户登录后加载它并以与存储信息相同的方式将其存储在商店中从登录响应。这样会快很多。
尝试使用 rxjs 管道进行内部可观察调用:flatMap 和 flatMapTo 或 mergeMap 或 mergeMapTo。在您的具体情况下,我认为 mergeMap 是可行的方法。
随意阅读 rxjs 中的那些管道,它们可能是解决方案