关于angular:具有第二个can的路由器无限循环在延迟加载的模块上激活防护

Router infinite loop with second canActivate guard on lazy-loaded modules

我有一个带有延迟加载模块的angular 4.3.6应用程序。这是部分根路由器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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 });

这两个示例模块中的子路由器:

车队:

1
2
3
4
5
6
7
RouterModule.forChild([
  {
    path: '',
    component: FleetComponent,
    canActivate: [AuthenticationGuard]
  }
]);

选择新密码:

1
2
3
4
5
6
7
RouterModule.forChild([
  {
    path: '',
    component: ChooseNewPasswordComponent,
    canActivate: [ChoosePasswordGuard]
  }
]);

AuthenticationGuard调用如下所示的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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做类似的事情,但仅保护选择新密码的组成部分(通常使用其他功能来设置密码):

1
2
3
4
5
6
7
8
return this.getUserSession().map((userSession: UserSession) => {
  if (userSession) {
    return userSession.expired;
  }
  else {
    return false;
  }
});

这在模块拆分之前有效。

现在,我陷入了重定向循环。启用路由器跟踪后,我观察到以下顺序。用户登录,并且AuthenticationGuard将改正重定向到/ password / set模块,并将其切换到ChooseNewPasswordGuard

  • NavigationStart(id:4,url:'/ password / set')
  • 已识别的Routes {id:4,URL:" / password / set",urlAfterRedirects:" / password / set",状态:RouterStateSnapshot}
  • GuardsCheckStart {id:4,url:" / password / set",urlAfterRedirects:UrlTree,状态:RouterStateSnapshot}
  • GuardsCheckEnd {id:4,URL:" / password / set",urlAfterRedirects:UrlTree,状态:RouterStateSnapshot,应激活:true}
  • NavigationCancel {id:4,URL:" / password / set",原因:"}
  • 此循环重复。

    (如果我将整个ChooseNewPasswordGuard替换为return Observable.of(true);,也会重复此操作)

    编辑:即使我在URL栏中提供/#/password/set,我也被重定向到根页面(/)...

    问题:

  • 既然模块是延迟加载的,我在路由器或防护装置上执行了强制此循环的错误操作吗?我对shouldActivate: true紧接着是NavigationCancel reason:""感到特别困惑。

  • 这与我直接在AuthenticationGuard中重定向有关,并且现在此防护应用于我的主空根路由({ path: '', redirectTo: 'fleet', pathMatch: 'full' }),它总是被调用并重定向,即使我设置路径了吗?

  • 我真的需要在子路径和根路径中重复canActivate防护吗?

  • 与往常一样,欢迎其他任何评论。


  • 问题是我过度使用了AuthenticationGuard:不应将其应用到顶级AppComponent,因为它将始终重定向到"选择新密码"模块,即使它正在加载该模块也是如此。铅>

    我的根routes应该看起来像这样:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    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模式。)