延迟加载模块上带有第二个 canActivate 守卫的路由器无限循环
Router infinite loop with second canActivate guard on lazy-loaded modules
我有一个带有延迟加载模块的 angular 4.3.6 应用程序。这是部分根路由器:
const routes: Routes = [
{ path: '', redirectTo: 'fleet', pathMatch: 'full' },
{
path: '',
component: AppComponent,
canActivate: [AuthenticationGuard],
children: [
{
path: 'fleet',
loadChildren: "./modules/fleet.module",
canActivate: [AuthenticationGuard]
},
{
path: 'password/set',
loadChildren: "./modules/chooseNewPassword.module",
canActivate: [ChoosePasswordGuard]
}
]
}
]
// Exports RouterModule.forRoot(routes, { enableTracing: true });
我在这两个示例模块中的子路由器:
舰队:
RouterModule.forChild([
{
path: '',
component: FleetComponent,
canActivate: [AuthenticationGuard]
}
]);
选择新密码:
RouterModule.forChild([
{
path: '',
component: ChooseNewPasswordComponent,
canActivate: [ChoosePasswordGuard]
}
]);
AuthenticationGuard
调用如下所示的方法:
return this.getUserSession().map((userSession: UserSession) => {
if (userSession && userSession.ok) {
return true;
}
else if (userSession && userSession.expired) {
this.router.navigate(['password/set'])
.catch((e: Error) => console.error(e));
return true;
}
else {
window.location.replace('/');
return false;
}
}
因此,如果用户的会话正常,它会激活路由。如果用户密码过期,它将用户重定向到选择新密码模块。如果没有会话,则重定向到登录。
ChoosePasswordGuard
做类似的事情,但只保护选择新密码组件(不同的工具用于一般设置密码):
return this.getUserSession().map((userSession: UserSession) => {
if (userSession) {
return userSession.expired;
}
else {
return false;
}
});
这在模块拆分之前有效。
现在,我陷入了重定向循环。启用路由器跟踪后,我观察到以下顺序。用户登录并且 AuthenticationGuard
更正重定向到 /password/set 模块,并移交给 ChooseNewPasswordGuard
:
- NavigationStart(id: 4, url: '/password/set')
- RoutesRecognized {id: 4, url: "/password/set", urlAfterRedirects: "/password/set",状态:RouterStateSnapshot}
- GuardsCheckStart {id: 4, url: "/password/set", urlAfterRedirects: UrlTree, state: RouterStateSnapshot}
- GuardsCheckEnd {id: 4, url: "/password/set", urlAfterRedirects: UrlTree, state: RouterStateSnapshot, shouldActivate: true}
- NavigationCancel {id: 4, url: "/password/set", 原因: ""}
然后这个循环重复。
(如果我用 return Observable.of(true);
替换整个 ChooseNewPasswordGuard 也会重复)
编辑:即使我在 URL 栏中提供 /#/password/set
,我也会被重定向到根页面 (/
)...
问题:
既然模块是延迟加载的,我在我的路由器或守卫中做错了什么来强制这个循环?我对 shouldActivate: true
后跟 NavigationCancel reason: ""
.
特别困惑
是不是和我直接在AuthenticationGuard中重定向,现在这个guard应用到我的主空根路由({ path: '', redirectTo: 'fleet', pathMatch: 'full' }
)有关系吗总是调用和重定向,即使我设置了路径?
我真的需要在子路由和根路由中重复 canActivate
守卫吗?
像往常一样,欢迎任何其他评论。
问题是我过度应用了 AuthenticationGuard
:它不应该应用到顶级 AppComponent 因为它总是会重定向到选择新密码模块,即使它正在加载那个模块。
我的根 routes
应该是这样的:
const routes: Routes = [
{ path: '', redirectTo: 'fleet', pathMatch: 'full' },
{
path: '',
component: AppComponent,
// canActivate: [AuthenticationGuard], // <-- Remove this guard
children: [
{
path: 'fleet',
loadChildren: "./modules/fleet.module",
canActivate: [AuthenticationGuard]
},
{
path: 'password/set',
loadChildren: "./modules/chooseNewPassword.module",
canActivate: [ChoosePasswordGuard]
}
]
}
]
(我欢迎并乐意接受更好的解释或更好的 AuthenticationGuard 模式。)
我有一个带有延迟加载模块的 angular 4.3.6 应用程序。这是部分根路由器:
const routes: Routes = [
{ path: '', redirectTo: 'fleet', pathMatch: 'full' },
{
path: '',
component: AppComponent,
canActivate: [AuthenticationGuard],
children: [
{
path: 'fleet',
loadChildren: "./modules/fleet.module",
canActivate: [AuthenticationGuard]
},
{
path: 'password/set',
loadChildren: "./modules/chooseNewPassword.module",
canActivate: [ChoosePasswordGuard]
}
]
}
]
// Exports RouterModule.forRoot(routes, { enableTracing: true });
我在这两个示例模块中的子路由器:
舰队:
RouterModule.forChild([
{
path: '',
component: FleetComponent,
canActivate: [AuthenticationGuard]
}
]);
选择新密码:
RouterModule.forChild([
{
path: '',
component: ChooseNewPasswordComponent,
canActivate: [ChoosePasswordGuard]
}
]);
AuthenticationGuard
调用如下所示的方法:
return this.getUserSession().map((userSession: UserSession) => {
if (userSession && userSession.ok) {
return true;
}
else if (userSession && userSession.expired) {
this.router.navigate(['password/set'])
.catch((e: Error) => console.error(e));
return true;
}
else {
window.location.replace('/');
return false;
}
}
因此,如果用户的会话正常,它会激活路由。如果用户密码过期,它将用户重定向到选择新密码模块。如果没有会话,则重定向到登录。
ChoosePasswordGuard
做类似的事情,但只保护选择新密码组件(不同的工具用于一般设置密码):
return this.getUserSession().map((userSession: UserSession) => {
if (userSession) {
return userSession.expired;
}
else {
return false;
}
});
这在模块拆分之前有效。
现在,我陷入了重定向循环。启用路由器跟踪后,我观察到以下顺序。用户登录并且 AuthenticationGuard
更正重定向到 /password/set 模块,并移交给 ChooseNewPasswordGuard
:
- NavigationStart(id: 4, url: '/password/set')
- RoutesRecognized {id: 4, url: "/password/set", urlAfterRedirects: "/password/set",状态:RouterStateSnapshot}
- GuardsCheckStart {id: 4, url: "/password/set", urlAfterRedirects: UrlTree, state: RouterStateSnapshot}
- GuardsCheckEnd {id: 4, url: "/password/set", urlAfterRedirects: UrlTree, state: RouterStateSnapshot, shouldActivate: true}
- NavigationCancel {id: 4, url: "/password/set", 原因: ""}
然后这个循环重复。
(如果我用 return Observable.of(true);
替换整个 ChooseNewPasswordGuard 也会重复)
编辑:即使我在 URL 栏中提供 /#/password/set
,我也会被重定向到根页面 (/
)...
问题:
既然模块是延迟加载的,我在我的路由器或守卫中做错了什么来强制这个循环?我对
shouldActivate: true
后跟NavigationCancel reason: ""
. 特别困惑
是不是和我直接在AuthenticationGuard中重定向,现在这个guard应用到我的主空根路由(
{ path: '', redirectTo: 'fleet', pathMatch: 'full' }
)有关系吗总是调用和重定向,即使我设置了路径?我真的需要在子路由和根路由中重复
canActivate
守卫吗?像往常一样,欢迎任何其他评论。
问题是我过度应用了 AuthenticationGuard
:它不应该应用到顶级 AppComponent 因为它总是会重定向到选择新密码模块,即使它正在加载那个模块。
我的根 routes
应该是这样的:
const routes: Routes = [
{ path: '', redirectTo: 'fleet', pathMatch: 'full' },
{
path: '',
component: AppComponent,
// canActivate: [AuthenticationGuard], // <-- Remove this guard
children: [
{
path: 'fleet',
loadChildren: "./modules/fleet.module",
canActivate: [AuthenticationGuard]
},
{
path: 'password/set',
loadChildren: "./modules/chooseNewPassword.module",
canActivate: [ChoosePasswordGuard]
}
]
}
]
(我欢迎并乐意接受更好的解释或更好的 AuthenticationGuard 模式。)