Last active
October 31, 2018 22:48
-
-
Save jasonaden/543853aa93b3fb369ad4570a502dcac8 to your computer and use it in GitHub Desktop.
Using Guards Redirect
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Guards execute in a similar way to how they used to. However, there is now prioritization involved. A guard | |
* closest to the root of the application takes priority, such that if guards for child routes return `false` | |
* or a `UrlTree` but parents haven't resolved yet, we will wait for the parents to resolve first. The highest | |
* prioirty failure (either `false` or `UrlTree` redirect) will take priority. | |
* | |
* If a `UrlTree` is returned from a guard, the current navigation will be cancelled (firing a `NavigationCancel` | |
* event) and a new navigation will be kicked off to the redirected URL. | |
*/ | |
// Example AuthGuardService | |
@Injectable() | |
export class AuthGuardService implements CanActivate { | |
constructor(public auth: AuthService, public router: Router) {} | |
// Notice this can now return UrlTree | |
canActivate(): Promise<boolean|UrlTree> { | |
return this.auth.isAuthenticated() | |
.then(isAuth => isAuth || this.router.parseUrl('/login'); | |
} | |
} | |
// Example simple promise based role guard | |
@Injectable() | |
export class RoleGuardService implements CanActivate { | |
constructor(public auth: AuthService, public router: Router) {} | |
canActivate(route: ActivatedRouteSnapshot): Promise<boolean|UrlTree> { | |
this.auth.getToken() | |
.then(token => { | |
if (this.auth.decode(token).role === route.data.expectedRole) { | |
return true; | |
else { | |
return this.router.parseUrl('/login'); | |
} | |
}); | |
} | |
} | |
// Synchronous guard to check if experiments is enabled in a query param | |
@Injectable() | |
export class ExperimentsGuardService implements CanActivate { | |
constructor(public router: Router) {} | |
canActivate(route: ActivatedRouteSnapshot, _, redirect): boolean|UrlTree { | |
if (route.queryParams.exp === 'enabled') { | |
return true; | |
} else { | |
return this.router.createUrlTree(['/error', {message: "Experiments are not enabled"}]); | |
} | |
} | |
} | |
export const ROUTES: Routes = [ | |
// Entire app is behind the `AuthGuardService`, and re-run on all route changes | |
{ path: '', | |
component: HomeComponent, | |
canActivate: [AuthGuardService], | |
runGuardsAndResolvers: 'always', | |
children: [ | |
{ path: 'profile', component: ProfileComponent }, | |
{ | |
path: 'admin', | |
component: AdminComponent, | |
canActivate: [RoleGuardService], | |
data: { | |
expectedRole: 'admin' | |
} | |
}, | |
{ | |
path: 'admin-new', | |
component: AdminNewComponent, | |
// Because this guard is in `children` of the parent route, when ExperimentsGuardService | |
// synchronously returns a UrlTree, it will wait for AuthGuardService of the parent | |
// route to finish resolving. If AuthGuardService returns `true`, the ExperimentsGuardService | |
// redirect will be followed. However, if AuthGuardService returns `UrlTree`, the | |
// ExperimentsGuardService redirect will be ignored and the redirect will be to the return | |
// of the AuthGuardService. | |
canActivate: [RoleGuardService, ExperimentsGuardService], | |
data: { | |
expectedRole: 'admin' | |
} | |
} | |
] | |
}, | |
{ path: '**', redirectTo: '' } | |
]; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment