路由器无限循环,第二个canActivate保护延迟加载模块

时间:2017-09-05 15:30:52

标签: angular lazy-loading angular-router angular-router-guards

我有一个带有延迟加载模块的角度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

  1. NavigationStart (id:4,url:'/ password / set')
  2. RoutesRecognized {id:4,url:“/ password / set”,urlAfterRedirects:“/ password / set”,state:RouterStateSnapshot}
  3. GuardsCheckStart {id:4,url:“/ password / set”,urlAfterRedirects:UrlTree,state:RouterStateSnapshot}
  4. GuardsCheckEnd {id:4,url:“/ password / set”,urlAfterRedirects:UrlTree,state:RouterStateSnapshot, shouldActivate:true }
  5. NavigationCancel {id:4,url:“/ password / set”,原因:“”}
  6. 这个循环重复。

    (如果我用return Observable.of(true);替换整个ChooseNewPasswordGuard,它也会重复)

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

    问题:

    1. 在我的路由器或防护装置中,由于模块是延迟加载的,所以我做错了什么?我对shouldActivate: true后跟NavigationCancel reason: ""

    2. 感到特别困惑
    3. 是否与我直接在AuthenticationGuard中重定向这一事实有关,现在该保护应用于我的主空根路由({ path: '', redirectTo: 'fleet', pathMatch: 'full' }),它总是被调用并重定向,甚至一旦我设定了路径?

    4. 我是否真的需要在我的孩子路线和我的根路线上重复canActivate后卫?

    5. 像往常一样,欢迎提出任何其他意见。

1 个答案:

答案 0 :(得分:2)

问题在于我过度应用AuthenticationGuard:它不应该应用于顶级AppComponent,因为它总是会重定向到Choose New Password模块,即使它正在加载该模块

我的根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 模式。)