Secure Angular Routes with Route Guards
Route guards are a crucial component of Angular applications, enabling you to control access to specific routes based on various conditions, such as user authentication or authorization. This challenge will guide you in implementing both CanActivate and CanDeactivate route guards to enhance the security and user experience of your Angular application.
Problem Description
You are tasked with creating an Angular application with two routes: /admin and /profile. The /admin route should only be accessible to authenticated users (simulated by a boolean isAuthenticated flag). The /profile route should prevent users from navigating away if they have unsaved changes in a form (simulated by a boolean hasUnsavedChanges). You need to implement CanActivate and CanDeactivate guards to enforce these restrictions.
Key Requirements:
CanActivateGuard for/admin: TheAdminGuardshould prevent access to the/adminroute ifisAuthenticatedisfalse.CanDeactivateGuard for/profile: TheProfileGuardshould prompt the user to confirm if they want to leave the/profileroute ifhasUnsavedChangesistrue. If the user confirms, navigation should be allowed; otherwise, it should be prevented.- Simulated Authentication and Unsaved Changes: For simplicity, use a global
isAuthenticatedflag (boolean) and ahasUnsavedChangesflag (boolean) to represent authentication status and form changes. These flags should be easily accessible within your guards. - User Confirmation: When
CanDeactivateis triggered, display a confirmation dialog to the user. The dialog should have "Stay" and "Leave" buttons. - Clear Navigation: The application should navigate to the
/profileroute when the user clicks the "Leave" button in the confirmation dialog.
Expected Behavior:
- Attempting to access
/adminwhenisAuthenticatedisfalseshould redirect the user to a designated "Unauthorized" route (e.g.,/unauthorized). - Attempting to navigate away from
/profilewhenhasUnsavedChangesistrueshould display a confirmation dialog. - Clicking "Stay" in the confirmation dialog should prevent navigation.
- Clicking "Leave" in the confirmation dialog should allow navigation to the intended route.
Edge Cases to Consider:
- What happens if the user refreshes the page while on the
/adminroute andisAuthenticatedisfalse? (The guard should still prevent access). - How should the confirmation dialog be styled and presented to the user? (Basic functionality is sufficient for this challenge).
- What happens if the user closes the browser window/tab while the confirmation dialog is open? (The guard should still prevent navigation, although the dialog might not be visible).
Examples
Example 1:
Input: isAuthenticated = false, User attempts to navigate to /admin
Output: User is redirected to /unauthorized
Explanation: AdminGuard prevents access because the user is not authenticated.
Example 2:
Input: isAuthenticated = true, hasUnsavedChanges = true, User attempts to navigate away from /profile
Output: A confirmation dialog appears with "Stay" and "Leave" buttons.
Explanation: ProfileGuard triggers the CanDeactivate guard.
Example 3:
Input: isAuthenticated = true, hasUnsavedChanges = false, User attempts to navigate away from /profile
Output: User is navigated away from /profile without any confirmation.
Explanation: ProfileGuard does not trigger the CanDeactivate guard because there are no unsaved changes.
Constraints
- The application should be a functional Angular application.
- Use Angular's built-in routing and guard mechanisms.
- The
isAuthenticatedandhasUnsavedChangesflags should be easily accessible (e.g., through a service). - The confirmation dialog should be implemented using Angular Material Dialog or a similar component library. Basic styling is acceptable.
- Focus on the core logic of the guards; elaborate UI/UX is not the primary focus.
- The application should be relatively simple and easy to understand.
Notes
- Consider using Angular's
ActivatedRouteandRouterservices within your guards to handle navigation. - The
CanActivateguard should return a boolean or aPromise<boolean>. - The
CanDeactivateguard should return a boolean or aPromise<boolean>. - Think about how to best structure your code to keep the guards clean and maintainable.
- You can simulate the "Unauthorized" route by simply displaying a message. No need to create a separate component for it.
- Remember to import necessary modules (e.g.,
RouterModule,MatDialogModule).