8

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

  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",原因: "" }

并且这个循环重复。

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

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

问题:

  1. 既然模块是延迟加载的,我在我的路由器或守卫中做错了什么来强制这个循环?我特别困惑,shouldActivate: true其次是NavigationCancel reason: ""

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

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

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

4

1 回答 1

10

问题是我过度应用了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模式。)

于 2017-09-05T15:42:52.707 回答