2

I'm trying to have an auth guard on every page of my Angular app. I can't get this to work for lazily loaded modules using the import() syntax.

My lazy feature module:

const routes: Routes = [
  {path: '', component: ExerciseGroupsMainPageComponent},
  {path: 'register-interests', component: RegisterInterestsComponent},
  {path: 'available-groups', component: AvailableGroupsPageComponent},
  {path: 'upcoming-sessions', component: UpcomingSessionsComponent}
]

@NgModule({
  declarations: [
    LocationsListComponent,
    LocationGroupsComponent,
    InterestCardComponent,
    TimeAfterDirective,
    RegisterInterestsComponent,
    AvailabilityCardComponent,
    ExerciseGroupsMainPageComponent,
    AvailableGroupsComponent,
    AvailableGroupsPageComponent,
    UpcomingSessionsComponent
  ],
  imports: [
    CommonAngularModule,
    LayoutModule,
    AppMaterialModule,
    FormsModule,
    FirebaseModule,
    CommonModule,
    RouterModule.forChild(routes)
  ],
  providers: [
    InterestsService,
    ActivitiesService,
    AvailabilitiesService
  ]
})
export class ExerciseGroupsModule { }

my main app routing module:

export const routes: Routes = [
  {path: '', redirectTo: 'groups', pathMatch: 'full'},
  {path: '', canActivateChild: [LoggedInGuard], children: [
    {component: RoutineListComponent, path: 'routines'},
    {component: SessionRunComponent, path: 'run-session', canActivate: [SessionRunGuard]},
    {component: RoutineConfigComponent, path: 'routine-config/:id'},
  ]},
  {
    path: 'groups', 
    canLoad: [LoggedInGuard], 
    canActivateChild: [LoggedInGuard], 
    canActivate: [LoggedInGuard], 
    loadChildren: () => import('./exercise-groups/exercise-groups.module')
      .then(m => m.ExerciseGroupsModule)
  },
  {component: LoginComponent, path: 'login'}
];

@NgModule({
  imports: [RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' })],
  exports: [RouterModule]
})
export class AppRoutingModule { }

My login guard:

@Injectable({
  providedIn: 'root'
})
export class LoggedInGuard implements CanActivateChild, CanLoad, CanActivate {
  
  constructor(private auth: AuthService, private router: Router, private snackBar: MatSnackBar) {}

  canActivateChild(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
      return this.auth.user$.pipe(
        map(u => {
          if (!u){
            this.router.navigate(['login']);
            this.snackBar.open('Please login or register to continue', 'OK');
          }

          return !!u;
        })
      );
  }

  canLoad(route: Route, segments: UrlSegment[]): boolean | UrlTree | Observable<boolean | UrlTree> | Promise<boolean | UrlTree> {
    console.log('canLoad called');
    return this.canActivateChild(null, null);
  }

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | UrlTree | Observable<boolean | UrlTree> | Promise<boolean | UrlTree> {
    return this.canActivateChild(null, null);
  }
  
}

I thought this would cause navigating to /upcoming-sessions in my feature module to navigate back to the login page when there was no user. However, the page still displays and no navigation occurs.If I put a console statement in all methods of the guard, they are not hit. How can I get the lazy-loaded children to be guarded?

Get Off My Lawn
  • 34,175
  • 38
  • 176
  • 338

0 Answers0