3

The use case: I want to redirect logged in users to /dashboard, and non-logged in users to /landing.

First take:

  {
    path: '**',
    redirectTo: '/dashboard',
    canActivate: [AuthGuard],
  },
  {
    path: '**',
    redirectTo: '/landing'
  }
@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {

  constructor(private auth: AuthService, private router: Router) {}

  canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean|UrlTree> | Promise<boolean|UrlTree> | boolean | UrlTree {
    return this.auth.isAuthenticated$
  }
}

All users are redirected to the dashboard page.

Second try:

  {
    path: '**',
    redirectTo: '/home/loggedin',
    canActivate: [AuthGuard],
    data: { authGuard: { redirect: '/home/loggedout' } }
  },
  {
    path: '**',
    redirectTo: '/home/loggedin'
  }
@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {

  constructor(private auth: AuthService, private router: Router) {}

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean|UrlTree> | Promise<boolean|UrlTree> | boolean | UrlTree {
    return this.auth.isAuthenticated$.pipe(
      map(loggedIn => {
        console.log(`A=${loggedIn} ${JSON.stringify(next.data.authGuard.redirect)}`)
        if (!loggedIn && next.data.authGuard.redirect) {
          return this.router.parseUrl(next.data.authGuard.redirect);
        } else {
          return false;
        }
      })
    );
  }
}

Seems like the AuthGuard is not even invoked. Possibly if I use a component instead of a redirect?

  {
    path: '**',
    component: RedirectingComponent,
    canActivate: [AuthGuard],
    data: { authGuard: { redirect: '/home/loggedout' }, redirectComponent: { redirect: '/home/loggedin' } }
  }

Now this seems to work, but it also is an awful hack.

How can AuthGuards be made to work with redirects?

Ákos Vandra-Meyer
  • 1,890
  • 1
  • 23
  • 40

2 Answers2

1

You can achieve this using children: [] instead of setting a component (like so)

{ 
  path: '', 
  canActivate: [AuthGuard], 
  children: [] 
}
minlare
  • 2,454
  • 25
  • 46
0

Your AuthGuard can force navigation. In your first try change the guard to something like this:

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {
  constructor(private auth: AuthService, private router: Router) {}

  canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean|UrlTree> | Promise<boolean|UrlTree> | boolean | UrlTree {
    // if user is authenticated just return true;
    if (this.auth.isAuthenticated$) { return true; }

    // if user is not authenticated redirect the user and return false
    this.router.navigate(['/landing']);
    return false;
  }
}

This should redirect unauthenticated users to landing page. You can also check the example in angular docs here.

wnvko
  • 1,985
  • 1
  • 14
  • 18
  • 2
    can you share what the route configuration you suggest to use this with? The guards are not executed for redirect routes... – Ákos Vandra-Meyer Mar 16 '20 at 11:41
  • 1
    I assume this answer advises to perform redirect in the CanActivate guard itself, and do not use `redirectTo` at all. – Yura Sep 16 '21 at 22:38