1

I am building an application, where I authenticate the user at the start of the application. Based on the whether the user has been authenticated or not, I want to lazy load a different angular module.

In context:

app.component.ts

@Component({
  template: `
    <app-splash-screen *ngIf="isAuthenticating$ | async; else main"></app-splash-screen>

    <ng-template #main>
      <router-outlet></router-outlet>
    </ng-template>
  `
})
export class AppComponent implements OnInit {
  readonly isAuthenticating$ = this.authFacade.isAuthenticating$;

  constructor(private readonly authFacade: AuthFacade) {}

  ngOnInit(): void {
    this.authFacade.authenticate();
  }
}

This is where I initiate my authentication logic that completes at an uncertain point in time. I can opt-in after completion with an Observable, if I need to.

When authentication has completed I load the router-outlet to the DOM.


app-routing.module.ts

const routes: Routes = [
  // Lazy-load, when authentication succeeds
  {
    path: '',
    pathMatch: 'full',
    loadChildren: () => import('@my-application/secret').then(m => m.SecretModule)
  },

  // Lazy-load, when authentication fails
  {
    path: 'home',
    loadChildren: () => import('@my-application/home').then(m => m.HomeModule)
  },
];

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

These are my top-level routes. Now, what I want to achieve is when the user has been authenticated, to lazy-load the SecretModule and display its contents.

On the other hand, when authentication fails, I want to navigate the user to the home page and lazy-load the HomeModule.

Now I see a problem regarding the blank route for the SecretModule. One work-around that I could think of is to implement this conditional routing logic elsewhere manually after authentication has completed, instead of doing it the 'angular way'.

What do you think might be the best approach here to implement said logic?

(I am using Angular 11 by the way)

1 Answers1

0

First you can add two guard so unauthorized users can't load and access your secret module:

auth.guard.ts

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate, CanLoad {
  constructor(
    private router: Router,
    private authService: AuthService, // I asume u got some kind of auth service written
  ) {}

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean | UrlTree> | boolean | UrlTree {
    console.log('Trying to activate admin route');
    return this.checkAccess();
  }

  canLoad(route: Route, segments: UrlSegment[]): Promise<boolean | UrlTree> | boolean | UrlTree {
    console.log('Trying to load admin  route');
    return this.checkAccess();
  }

  private checkAccess(): Promise<boolean | UrlTree> {
    return new Promise<boolean | UrlTree>(async (resolve) => {
      // Do your check here if the user is authenticated
      const isLoggedIn = await this.authService.isLoggedIn();

      // If user is not authenticated he gets redirected to home page
      resolve(isLoggedIn ? true : this.router.createUrlTree(['home']));
    });
  }
}

Then simply use your guards on your secret route:

const routes: Routes = [
  // Lazy-load, when authentication succeeds
  {
    path: '',
    pathMatch: 'full',
    loadChildren: () => import('@my-application/secret').then(m => m.SecretModule),
    canLoad: [AuthGuard],
    canActivate: [AuthGuard],
  },

  // Lazy-load, when authentication fails
  {
    path: 'home',
    loadChildren: () => import('@my-application/home').then(m => m.HomeModule)
  },
];

You can read more on guard in the docs

Norbert Bartko
  • 2,468
  • 1
  • 17
  • 36
  • 1
    Thanks, that really helped me out. I didn't think of guards at first for solving this. – AndriWandres Dec 14 '20 at 11:05
  • 1
    But does it make any difference to also add a `CanActivate` guard when there is already a `CanLoad` guard in place? Wouldn't the `CanLoad` be sufficient for restricting access? (When the module is not loaded, it cannot be accessed) – AndriWandres Dec 14 '20 at 11:07
  • Nah not rly, when u only use only the `CanLoad` guard and the user logs out he can still `activate` the secret route by navigating back – Norbert Bartko Dec 14 '20 at 11:12