Бесконечный цикл маршрутизатора со второй canActivate guard on lazy-loaded modules

У меня есть угловое приложение 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. Как обычно, приветствуются любые другие комментарии.


person msanford    schedule 05.09.2017    source источник


Ответы (1)


Проблема заключалась в том, что я чрезмерно применял 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.)

person msanford    schedule 05.09.2017
comment
Значит, «пароль / набор» не нужно защищать с помощью AuthenticationGuard? - person Anjil Dhamala; 12.03.2019
comment
@AnjilDhamala Верно, у него, как вы можете видеть, есть собственная защита, которая частично реализует логику AuthenticationGuard, но позволяет вам получить доступ только к одному маршруту. - person msanford; 14.03.2019
comment
Спасибо, что вернулись. На самом деле я обнаружил, что у меня проблемы с настройкой ngrx. Я застрял в аду изменения состояния, когда страница входа была подписана на изменения состояния и перенаправлялась на определенную страницу, когда состояние возвращало URL-адрес перенаправления. К сожалению, навигация отметила врасплох проверки, и страница, которую я пытался использовать с помощью deeplink, сделала еще один вызов действия ngrx, который продолжал изменять состояние, а моя страница входа в систему продолжала пытаться отреагировать на это изменение. Таким образом, сбой моего браузера. - person Anjil Dhamala; 14.03.2019
comment
@AnjilDhamala А, возможно, в вашем случае следует отметить то, что наша страница входа на самом деле находится за пределами приложения angular и обслуживается JBoss, который затем перенаправляется на Angular. Все наше приложение Angular требует аутентификации. Хорошо, что вы дочитали до конца! Я уверен, что вы можете задать вопрос об этом прямо сейчас. - person msanford; 14.03.2019