How can you use Angular canActivate to deny the result of protection?

From the Angular documentation on canActivate , it looks like you can only use canActivate security devices to allow the transition to the route if the canActivate function ultimately returns true .

Is it possible to say, "just go to this route if the canActivate class evaluates to false "?

For example, in order to prevent users from entering the login page, I tried this, but it did not work:

 export const routes: Route[] = [ { path: 'log-in', component: LoginComponent, canActivate: [ !UserLoggedInGuard ] }, 

I got this error in the console:

 ERROR Error: Uncaught (in promise): Error: StaticInjectorError[false]: StaticInjectorError[false]: NullInjectorError: No provider for false! Error: StaticInjectorError[false]: StaticInjectorError[false]: NullInjectorError: No provider for false! 
+13
angular typescript angular-routing
source share
3 answers

Interesting in your question is the wording:

Is there a way to say: "Go to this route if the canActivate class evaluates to false "

And as you expressed the β€œintuitive” solution:

 { path: 'log-in', component: LoginComponent, canActivate: [ !UserLoggedInGuard ] }, 

Which basically says you need to negate result UserLoggedInGuard@canActivate

Consider the following implementation of UserLoggedInGuard :

 @Injectable() export class UserLoggedInGuard implements CanActivate { constructor(private _authService: AuthService) {} canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { return this._authService.isLoggedIn(); } } 

Next, consider the solution proposed by @Mike

 @Injectable() export class NegateUserLoggedInGuard implements CanActivate { constructor(private _authService: AuthService) {} canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { return !this._authService.isLoggedIn(); } } 

The approach is now approved, but closely related to the (internal) implementation of UserLoggedInGuard . If, for some reason, the implementation of UserLoggedInGuard@canActivate changes, NegateUserLoggedInGuard will break.

How can we avoid this? Simple abuse addiction injection:

 @Injectable() export class NegateUserLoggedInGuard implements CanActivate { constructor(private _userLoggedInGuard: UserLoggedInGuard) {} canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { return !this._userLoggedInGuard.canActivate(route,state); } } 

Now it does exactly what you expressed with

 canActivate: [ !UserLoggedInGuard ] 

And the best part:

  • It is not closely related to the internal implementation of UserLoggedInGuard
  • Can be extended to manage the result of more than one Guard class
+8
source share

When thinking about your problem, one solution might be to implement route protection, which reverses the logic.

 import { MyService } from "./myservice.service"; import { CanActivate, RouterStateSnapshot, ActivatedRouteSnapshot } from "@angular/router"; import { Injectable } from "@angular/core"; @Injectable() export class MyGuard implements CanActivate { constructor(private myService: MyService) {} canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { return this.myService.isNotLoggedIn(); //if user not logged in this is true } } 
+2
source share

I had a similar problem - I wanted to create a login page that would be accessible only if it did not authenticate, and the dashboard - only if you were authenticated (and redirect the user to the corresponding page automatically ) I solved this by making the guard login + route sensitive:

Routes:

 const appRoutes: Routes = [ { path: 'login', component: LoginComponent, canActivate: [AuthGuard] }, { path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] }, 

Sentinel:

 export class AuthGuard implements CanActivate { private login: UrlTree; private dash: UrlTree; constructor(private authSvc: AuthenticationService, private router: Router ) { this.login = this.router.parseUrl('login'); this.dash = this.router.parseUrl('dashboard'); } canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | UrlTree { if (this.authSvc.isSignedIn()) { if (route.routeConfig.path === 'login') { return this.dash; } else { return true; } } else { if (route.routeConfig.path === 'login') { return true; } else { return this.login; } } } } 
0
source share

All Articles