Search code examples
angularauthenticationangular-routinguser-rolesangular-guards

Angular router: navigating to different routes according to the user's role


I'm writing a mock e-commerce app which has the following structure:

  • app
    • auth
      • sign-in-page
      • sign-up-page
      • auth-routing.module.ts
        const routes: Routes = [
          {
            path: 'signup',
            component: SignUpPage,
          },
          {
            path: 'signin',
            component: SignInPage,
          },
        ];
        
      • auth.module.ts
    • admin
      • root-page
      • admin-routing.module.ts
        const routes: Routes = [
          {
            path: 'admin',
            component: RootPage,
            children: [
              // ...                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
            ],
          },
        ];
        
      • admin.modules.ts
    • customer
      • root-page
      • catalog-page
      • check-out-page
      • thank-you-page
      • customer-routing.module.ts
        const routes: Routes = [
          {
            path: 'customer',
            component: RootPage,
            children: [
              { path: 'catalog/:categoryId', component: CatalogPage },
              { path: 'checkout', component: CheckOutPage },
              { path: 'thankyou', component: ThankYouPage },
            ],
          },
        ];
        
      • customer.module.ts
    • page-not-found
    • app-routing.module.ts
      const routes: Routes = [
        { path: '**', component: NotFoundPage },
      ];
      
    • app.module.ts
    • app.component.html
    • app.component.css

The basic workflow is supposed to be as follows:

  1. The user navigates to the root path /.
  2. The application detects that they are not logged in, so it redirects them to /signin.
  3. They enter their credentials and press Sign In.
  4. If the authentication is successful,
    1. If the user is an admin, they get redirected to /admin.
      1. admin-router.module.ts redirects them to some sub-path of /admin.
    2. If the user is a customer, they get redirected to /customer.
      1. customer-router.module.ts redirects them to /customer/catalog/<default category ID>.
      2. They put some products in the shopping cart and proceed to /customer/checkout.
      3. They place the order and get redirected to /customer/thankyou.

What I'm not sure about is how to accomplish the redirection following a successful log-in. Obviously it has to be done in two stages: first to some common path such as / and then either to /customer or to /admin depending on the user's role. The second stage probably needs to be handled by app-routing.module.ts, perhaps using a guard, but I'm not sure exactly how to do it.

EDIT (2021-04-20)

The problem can be summarized as follows:

What I need is a way (preferably declarative) to redirect the application from / to one of the following paths depending on its state:

State Path
Logged out /auth
Logged in as a customer /customer
Logged in as an admin /admin

Solution

  • What I ended up doing is this:

    // app-routing.module.ts
    
    const routes: Routes = [
      {
        path: '',
        canActivate: [AuthorizationGuard],
        children: [],
      },
      { path: '**', component: NotFoundPage },
    ];
    
    // authorization.guard.ts
    
    @Injectable({
      providedIn: 'root',
    })
    export class AuthorizationGuard implements CanActivate {
    
      constructor(private router: Router, private authService: AuthService) {}
    
      canActivate(
        route: ActivatedRouteSnapshot,
        state: RouterStateSnapshot
      ): UrlTree {
        const user = this.authService.getLoggedInUser();
        return (
          (user?.role === 'admin' && this.router.parseUrl('/admin')) ||
          (user?.role === 'customer' && this.router.parseUrl('/customer')) ||
          this.router.parseUrl('/auth')
        );
      }
    
    }