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:
- 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. - 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
AuthGuardthat checks for an authentication status. - Implement an
AdminGuardthat checks for an administrator role, assuming authentication is already handled byAuthGuard. - Both guards should implement the
CanActivateinterface from@angular/router. - The guards should be able to access a hypothetical
AuthServiceandUserService(which you will need to mock or simulate for testing purposes). - The guards should return
trueto allow navigation,falseto block navigation, or aUrlTreefor 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
/loginand navigation should be blocked (UrlTree('/login')).
- If a user is logged in, navigation to the protected route should be allowed (
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,
AuthGuardshould ideally handle this redirection first. If for some reasonAdminGuardis reached without authentication, it should also redirect to/login.
- If a user is logged in AND is an administrator, navigation to the protected route should be allowed (
Edge Cases:
- What happens if a user navigates directly to a route protected by
AdminGuardwithout 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
AuthServicereturnstrueforisAuthenticated(). They click a link to/dashboard. - Output: The
AuthGuard'scanActivatemethod returnstrue. The user successfully navigates to theDashboardComponent. - Explanation: The
AuthGuardpermits access because the user is authenticated.
Example 2: Unauthenticated User Navigates to Dashboard
- Input: A user is NOT logged in, and their
AuthServicereturnsfalseforisAuthenticated(). They click a link to/dashboard. - Output: The
AuthGuard'scanActivatemethod returns aUrlTreeredirecting to/login. The user is redirected to theLoginComponent. - Explanation: The
AuthGuardprevents 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()returnstrue, but theirUserService.isAdmin()returnsfalse. They try to navigate to/admin-panel. - Output: The
AuthGuardallows navigation (returnstrue). TheAdminGuard'scanActivatemethod is then called and returns aUrlTreeredirecting to/forbidden. The user is redirected to theForbiddenComponent. - Explanation: The
AuthGuardallows the request to proceed, but theAdminGuardintercepts 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()returnstrue, and theirUserService.isAdmin()returnstrue. They try to navigate to/admin-panel. - Output: The
AuthGuardallows navigation (true). TheAdminGuardalso allows navigation (true). The user successfully navigates to theAdminPanelComponent. - 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
AuthGuardandAdminGuardclasses that implementCanActivate. - You will need to create mock implementations for
AuthServiceandUserServiceto demonstrate and test your guards. These mocks should expose methods likeisAuthenticated()(returning boolean) andisAdmin()(returning boolean). - The redirection targets (
/loginand/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/falsereturn values orUrlTreeare 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.