docs(router): Update router guide to use UrlTree for guard redirects (#37100)
The current implementation for redirecting users inside guards was in place before the feature was added to allow `CanActivate` and `CanActivateChild` guards to return `UrlTree` for redirecting users. Returning `UrlTree` should be the default method, as it provides a more desirable redirecting experience. When using `router.navigate` followed by `return false`, the `Router` calls `resetUrlToCurrentUrlTree` (in the `finalize` operator) before processing the navigation to the new route. This can result in an undesirable history if the navigation was the first navigation in the application - that is, the route will briefly be reset to just `/` (see #36187). Fixes #36187 PR Close #37100
This commit is contained in:
parent
77c0ef38be
commit
8a56c99f87
|
@ -1,6 +1,6 @@
|
|||
// #docregion
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
|
||||
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router, UrlTree } from '@angular/router';
|
||||
|
||||
import { AuthService } from './auth.service';
|
||||
|
||||
|
@ -12,21 +12,20 @@ export class AuthGuard implements CanActivate {
|
|||
|
||||
canActivate(
|
||||
next: ActivatedRouteSnapshot,
|
||||
state: RouterStateSnapshot): boolean {
|
||||
state: RouterStateSnapshot): true|UrlTree {
|
||||
let url: string = state.url;
|
||||
|
||||
return this.checkLogin(url);
|
||||
}
|
||||
|
||||
checkLogin(url: string): boolean {
|
||||
checkLogin(url: string): true|UrlTree {
|
||||
if (this.authService.isLoggedIn) { return true; }
|
||||
|
||||
// Store the attempted URL for redirecting
|
||||
this.authService.redirectUrl = url;
|
||||
|
||||
// Navigate to the login page with extras
|
||||
this.router.navigate(['/login']);
|
||||
return false;
|
||||
// Redirect to the login page
|
||||
return this.router.parseUrl('/login');
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
|
|
@ -4,7 +4,8 @@ import {
|
|||
CanActivate, Router,
|
||||
ActivatedRouteSnapshot,
|
||||
RouterStateSnapshot,
|
||||
CanActivateChild
|
||||
CanActivateChild,
|
||||
UrlTree
|
||||
} from '@angular/router';
|
||||
import { AuthService } from './auth.service';
|
||||
|
||||
|
@ -16,7 +17,7 @@ export class AuthGuard implements CanActivate, CanActivateChild {
|
|||
|
||||
canActivate(
|
||||
route: ActivatedRouteSnapshot,
|
||||
state: RouterStateSnapshot): boolean {
|
||||
state: RouterStateSnapshot): true|UrlTree {
|
||||
let url: string = state.url;
|
||||
|
||||
return this.checkLogin(url);
|
||||
|
@ -24,20 +25,19 @@ export class AuthGuard implements CanActivate, CanActivateChild {
|
|||
|
||||
canActivateChild(
|
||||
route: ActivatedRouteSnapshot,
|
||||
state: RouterStateSnapshot): boolean {
|
||||
state: RouterStateSnapshot): true|UrlTree {
|
||||
return this.canActivate(route, state);
|
||||
}
|
||||
|
||||
// #enddocregion can-activate-child
|
||||
checkLogin(url: string): boolean {
|
||||
checkLogin(url: string): true|UrlTree {
|
||||
if (this.authService.isLoggedIn) { return true; }
|
||||
|
||||
// Store the attempted URL for redirecting
|
||||
this.authService.redirectUrl = url;
|
||||
|
||||
// Navigate to the login page
|
||||
this.router.navigate(['/login']);
|
||||
return false;
|
||||
// Redirect to the login page
|
||||
return this.router.parseUrl('/login');
|
||||
}
|
||||
// #docregion can-activate-child
|
||||
}
|
||||
|
|
|
@ -6,7 +6,8 @@ import {
|
|||
ActivatedRouteSnapshot,
|
||||
RouterStateSnapshot,
|
||||
CanActivateChild,
|
||||
NavigationExtras
|
||||
NavigationExtras,
|
||||
UrlTree
|
||||
} from '@angular/router';
|
||||
import { AuthService } from './auth.service';
|
||||
|
||||
|
@ -16,17 +17,17 @@ import { AuthService } from './auth.service';
|
|||
export class AuthGuard implements CanActivate, CanActivateChild {
|
||||
constructor(private authService: AuthService, private router: Router) {}
|
||||
|
||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
|
||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): true|UrlTree {
|
||||
let url: string = state.url;
|
||||
|
||||
return this.checkLogin(url);
|
||||
}
|
||||
|
||||
canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
|
||||
canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): true|UrlTree {
|
||||
return this.canActivate(route, state);
|
||||
}
|
||||
|
||||
checkLogin(url: string): boolean {
|
||||
checkLogin(url: string): true|UrlTree {
|
||||
if (this.authService.isLoggedIn) { return true; }
|
||||
|
||||
// Store the attempted URL for redirecting
|
||||
|
@ -42,8 +43,7 @@ export class AuthGuard implements CanActivate, CanActivateChild {
|
|||
fragment: 'anchor'
|
||||
};
|
||||
|
||||
// Navigate to the login page with extras
|
||||
this.router.navigate(['/login'], navigationExtras);
|
||||
return false;
|
||||
// Redirect to the login page with extras
|
||||
return this.router.createUrlTree(['/login'], navigationExtras);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2737,7 +2737,7 @@ If the user is logged in, it returns true and the navigation continues.
|
|||
The `ActivatedRouteSnapshot` contains the _future_ route that will be activated and the `RouterStateSnapshot` contains the _future_ `RouterState` of the application, should you pass through the guard check.
|
||||
|
||||
If the user is not logged in, you store the attempted URL the user came from using the `RouterStateSnapshot.url` and tell the router to redirect to a login page—a page you haven't created yet.
|
||||
This secondary navigation automatically cancels the current navigation; `checkLogin()` returns `false`.
|
||||
Returning a `UrlTree` tells the `Router` to cancel the current navigation and schedule a new one to redirect the user.
|
||||
|
||||
{@a add-login-component}
|
||||
|
||||
|
@ -2790,8 +2790,8 @@ Extend the `AuthGuard` to protect when navigating between the `admin` routes.
|
|||
Open `auth.guard.ts` and add the `CanActivateChild` interface to the imported tokens from the router package.
|
||||
|
||||
Next, implement the `canActivateChild()` method which takes the same arguments as the `canActivate()` method: an `ActivatedRouteSnapshot` and `RouterStateSnapshot`.
|
||||
The `canActivateChild()` method can return an `Observable<boolean>` or `Promise<boolean>` for async checks and a `boolean` for sync checks.
|
||||
This one returns a `boolean`:
|
||||
The `canActivateChild()` method can return an `Observable<boolean|UrlTree>` or `Promise<boolean|UrlTree>` for async checks and a `boolean` or `UrlTree` for sync checks.
|
||||
This one returns either `true` to allow the user to access the admin feature module or `UrlTree` to redirect the user to the login page instead:
|
||||
|
||||
<code-example path="router/src/app/auth/auth.guard.3.ts" header="src/app/auth/auth.guard.ts (excerpt)" region="can-activate-child"></code-example>
|
||||
|
||||
|
|
Loading…
Reference in New Issue