Hone logo
Hone
Problems

Implementing Angular Route Guards for Authentication and Authorization

This challenge focuses on implementing crucial security features in an Angular application by creating custom route guards. Route guards are essential for controlling access to specific routes, ensuring that only authenticated and authorized users can navigate to protected sections of your application.

Problem Description

Your task is to create two distinct Angular route guards:

  1. Authentication Guard (AuthGuard): This guard will protect routes that require a user to be logged in. If the user is not authenticated, they should be redirected to a login page.
  2. Authorization Guard (AdminGuard): This guard will protect routes that require specific administrative privileges. If the user is authenticated but not an administrator, they should be prevented from accessing the route and potentially shown an error message or redirected to a "forbidden" page.

Key Requirements:

  • Implement an AuthGuard that checks for an authentication status.
  • Implement an AdminGuard that checks for an administrator role, assuming authentication is already handled by AuthGuard.
  • Both guards should implement the CanActivate interface from @angular/router.
  • The guards should be able to access a hypothetical AuthService and UserService (which you will need to mock or simulate for testing purposes).
  • The guards should return true to allow navigation, false to block navigation, or a UrlTree for redirection.

Expected Behavior:

  • AuthGuard:
    • If a user is logged in, navigation to the protected route should be allowed (true).
    • If a user is not logged in, they should be redirected to /login and navigation should be blocked (UrlTree('/login')).
  • AdminGuard:
    • If a user is logged in AND is an administrator, navigation to the protected route should be allowed (true).
    • If a user is logged in BUT is NOT an administrator, they should be redirected to /forbidden (or a similar route) and navigation should be blocked (UrlTree('/forbidden')).
    • If the user is not logged in, AuthGuard should ideally handle this redirection first. If for some reason AdminGuard is reached without authentication, it should also redirect to /login.

Edge Cases:

  • What happens if a user navigates directly to a route protected by AdminGuard without being authenticated?
  • How do you handle the scenario where the authentication or user role check takes time (e.g., asynchronous operations)? (Though for this challenge, synchronous checking is sufficient, understanding the asynchronous nature is a plus).

Examples

Let's assume we have a simple routing setup:

// app-routing.module.ts (simplified)
const routes: Routes = [
  { path: 'login', component: LoginComponent },
  {
    path: 'dashboard',
    component: DashboardComponent,
    canActivate: [AuthGuard]
  },
  {
    path: 'admin-panel',
    component: AdminPanelComponent,
    canActivate: [AuthGuard, AdminGuard] // Both guards are applied
  },
  { path: 'forbidden', component: ForbiddenComponent },
  { path: '**', redirectTo: 'dashboard' } // Fallback
];

Example 1: Authenticated User Navigates to Dashboard

  • Input: A user is logged in, and their AuthService returns true for isAuthenticated(). They click a link to /dashboard.
  • Output: The AuthGuard's canActivate method returns true. The user successfully navigates to the DashboardComponent.
  • Explanation: The AuthGuard permits access because the user is authenticated.

Example 2: Unauthenticated User Navigates to Dashboard

  • Input: A user is NOT logged in, and their AuthService returns false for isAuthenticated(). They click a link to /dashboard.
  • Output: The AuthGuard's canActivate method returns a UrlTree redirecting to /login. The user is redirected to the LoginComponent.
  • Explanation: The AuthGuard prevents access and redirects the user to the login page.

Example 3: Authenticated Non-Admin User Navigates to Admin Panel

  • Input: A user is logged in, AuthService.isAuthenticated() returns true, but their UserService.isAdmin() returns false. They try to navigate to /admin-panel.
  • Output: The AuthGuard allows navigation (returns true). The AdminGuard's canActivate method is then called and returns a UrlTree redirecting to /forbidden. The user is redirected to the ForbiddenComponent.
  • Explanation: The AuthGuard allows the request to proceed, but the AdminGuard intercepts it due to insufficient privileges and redirects to the forbidden page.

Example 4: Authenticated Admin User Navigates to Admin Panel

  • Input: A user is logged in, AuthService.isAuthenticated() returns true, and their UserService.isAdmin() returns true. They try to navigate to /admin-panel.
  • Output: The AuthGuard allows navigation (true). The AdminGuard also allows navigation (true). The user successfully navigates to the AdminPanelComponent.
  • Explanation: Both guards confirm the user meets the necessary criteria for access.

Constraints

  • The solution must be implemented using TypeScript and Angular.
  • You are expected to create AuthGuard and AdminGuard classes that implement CanActivate.
  • You will need to create mock implementations for AuthService and UserService to demonstrate and test your guards. These mocks should expose methods like isAuthenticated() (returning boolean) and isAdmin() (returning boolean).
  • The redirection targets (/login and /forbidden) are assumed to be valid routes in your application.

Notes

  • Consider how you would handle asynchronous operations in a real-world scenario (e.g., checking tokens from a backend). For this challenge, synchronous true/false return values or UrlTree are sufficient.
  • Think about the order in which guards are applied in the route configuration. The order can be significant, especially when using multiple guards.
  • Success looks like having two functional route guards that correctly control access to different parts of an Angular application based on authentication and administrative roles.
Loading editor...
typescript