带有第二个 canActivate 对延迟加载模块的保护的路由器无限循环

msa*_*ord 7 lazy-loading angular angular-router-guards angular-router

我有一个带有延迟加载模块的 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 });
Run Code Online (Sandbox Code Playgroud)

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

舰队:

RouterModule.forChild([
  {
    path: '',
    component: FleetComponent,
    canActivate: [AuthenticationGuard]
  }
]);
Run Code Online (Sandbox Code Playgroud)

选择新密码:

RouterModule.forChild([
  {
    path: '',
    component: ChooseNewPasswordComponent,
    canActivate: [ChoosePasswordGuard]
  }
]);
Run Code Online (Sandbox Code Playgroud)

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

所以,如果用户的会话没问题,它就会激活路由。如果用户的密码已过期,它会将用户重定向到选择新密码模块。如果没有会话,则重定向到登录。

ChoosePasswordGuard做类似的事情,但不仅保护了选择新的密码组件(不同的设备用于一般设置密码):

return this.getUserSession().map((userSession: UserSession) => {
  if (userSession) {
    return userSession.expired;
  }
  else {
    return false;
  }
});
Run Code Online (Sandbox Code Playgroud)

这在模块拆分之前有效。

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

  1. NavigationStart (id: 4, url: '/password/set')
  2. 路线识别 {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", reason: "" }

并且这个循环重复。

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

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

问题:

  1. 既然模块是延迟加载的,我在路由器或警卫中做错了什么来强制执行此循环?我特别困惑,shouldActivate: true后面跟着NavigationCancel reason: "".

  2. 它是否与我直接在 AuthenticationGuard 中重定向的事实有关,现在这个防护应用于我的主要空根路由 ( { path: '', redirectTo: 'fleet', pathMatch: 'full' }) 它总是被调用和重定向,即使我已经设置了路径?

  3. 我真的需要canActivate在我的子路由和根路由中重复守卫吗?

  4. 像往常一样,欢迎任何其他评论。

msa*_*ord 8

问题是我过度应用了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]
      }
    ]
  }
]
Run Code Online (Sandbox Code Playgroud)

(我欢迎并乐意接受更好的解释或更好的AuthenticationGuard模式。)