Angular 2 AuthGuard Service with redirect?

I have an application that I am building that implements CanActivate on the dashboard route. It works fine except on page reload, I check a flag in the user service to see if a user is logged in or not. By default this flag is false which kicks the user out to login. Also on page reload I am trying to fetch user data with a token in localStorage, if fetch is successful, I want them to be able to stay on the dashboard. The problem is that I am seeing a glimpse of login and having to manually redirect them to the dashboard. Is there any way to fix this to where the authGuard doesn’t do anything until after it checks the API? Code is here: https://github.com/judsonmusic/tfl

dashboard:

import { Component, ViewChild } from '@angular/core';
import { LoginComponent } from "../login.component";
import { UserService } from "../user.service";
import { SimpleChartComponent } from "../charts/simpleChart.component";
import { AppleChartComponent } from "../charts/appleChart.component";
import { BarChartComponent } from "../charts/barChart.component";
import { DonutChartComponent } from "../charts/donutChart.component";
import { AlertComponent } from 'ng2-bootstrap/ng2-bootstrap';
import { ModalDemoComponent } from "../modals/modalDemoComponent";
import { NgInitHelperComponent } from "../helpers/nginit.helper.component";
import { ModalDirective } from "ng2-bootstrap/ng2-bootstrap";
import { MODAL_DIRECTIVES, BS_VIEW_PROVIDERS } from 'ng2-bootstrap/ng2-bootstrap';


@Component({
  selector: 'dashboard',
  templateUrl: '/app/components/dashboard/dashboard.component.html',
  providers: [UserService, BS_VIEW_PROVIDERS],
  directives: [SimpleChartComponent, AppleChartComponent, BarChartComponent, DonutChartComponent, AlertComponent, ModalDemoComponent, NgInitHelperComponent, ModalDirective]
})
export class DashboardComponent  {

  public areas: any;

  constructor() {

    this.areas = [
      "Spiritual",
      "Habits",
      "Relationships",
      "Emotional",
      "Eating Habits",
      "Relaxation",
      "Exercise",
      "Medical",
      "Financial",
      "Play",
      "Work/ Life Balance",
      "Home Environment",
      "Intellectual Well-being",
      "Self Image",
      "Work Satisfaction"
    ]

  }
}

Routes:

import { Routes, RouterModule } from '@angular/router';
import { AboutComponent } from './components/about.component';
import { PageNotFoundComponent } from "./components/pageNotFound.component";
import { HomeComponent } from "./components/home.component";
import { DashboardComponent } from "./components/dashboard/dashboard.component";
import { SurveyComponent } from "./components/survey/survey.component";
import { ResourcesComponent } from "./components/resources.component";
import { LogoutComponent } from "./components/logout.component";
import { AuthGuard } from "./components/auth-guard.service";
import { loginRoutes, authProviders } from './login.routing';
import { LoginComponent } from "./components/login.component";

const appRoutes:Routes = [
  { path: '', component: HomeComponent },
  { path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] },
  { path: 'logout', component: LogoutComponent },
  { path: 'resources', component: ResourcesComponent },
  { path: 'survey', component: SurveyComponent },
  { path: 'about', component: AboutComponent },
  { path: 'login', component: LoginComponent },
  { path: '**', component: PageNotFoundComponent }
];

export const appRoutingProviders: any[] = [
  authProviders
];
export const routing = RouterModule.forRoot(appRoutes);

login route:

import { Routes }         from '@angular/router';
import { AuthGuard }      from './components/auth-guard.service';
import { AuthService }    from './components/auth.service';
import { LoginComponent } from './components/login.component';
export const loginRoutes: Routes = [
  { path: 'login', component: LoginComponent }
];
export const authProviders = [
  AuthGuard,
  AuthService
];

5 thoughts on “Angular 2 AuthGuard Service with redirect?”

  1. I actually changed my service to this and it works:

    import { Injectable }             from '@angular/core';
    import { CanActivate, Router,
    ActivatedRouteSnapshot,
    RouterStateSnapshot }    from '@angular/router';
    import { AuthService }            from './auth.service';
    import {UserService} from "./user.service";
    
    @Injectable()
    export class AuthGuard implements CanActivate {
      constructor(private authService: AuthService, private router: Router, private userService: UserService) {}
    
      canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    
    
    
        if (this.authService.isLoggedIn){
          console.log('ATUH GUARD SAYD THEY ARE ALREADY LOGGED IN!');
          return true;
    
    
        }else {
    
    
          this.userService.getUser().subscribe((user) => {
    
            console.log('AUTH GUARD GETTING USER', user);
    
            if (user._id) {
            this.authService.isLoggedIn = true;
            // Store the attempted URL for redirecting
            this.authService.redirectUrl = state.url;
            this.router.navigate(['/dashboard']);
            return true;
            }else{
              console.log('Validation Failed.');
              localStorage.clear();
              this.router.navigate(['/login']);
              return false;
            }
    
    
          }, (error) => {
            console.log('There was an error.');
            this.router.navigate(['/login']);
            return false
    
          });
    
        }
    
    
      }
    }
    
    Reply
  2. You can now return a UrlTree from an AuthGuard, or a boolean true / false.

    Kind of amazed nobody has mentioned this yet! Sorry no example right now, but the idea is pretty simple.

    Reply
  3. In AuthGuard do the following:

    @Injectable()
    export class AuthGuard implements CanActivate {
      constructor(private authService: AuthService, private router: Router) {}
    
      canActivate() {
        if (/*user is logged in*/) {
          this.router.navigate(['/dashboard']);
          return true;
        } else {
          this.router.navigate(['/Login']);
        }
        return false;
      }
    }
    
    Reply
  4. I solved it like this and used it in my AuthGuard

    isLoggedIn(): Observable<boolean> {
    return this.afAuth.authState
      .pipe(
        take(1),
        map(user => {
            return !!user;
          },
          () => {
            return false;
          }
        ),
        tap(loggedIn => {
            if (!loggedIn) {
              this.router.navigate(['/']);
            }
          }
        ));
    }
    
    Reply
  5. Here’s how to correctly handle redirects in a guard by using an UrlTree

    @Injectable({
      providedIn: 'root'
    })
    export class AuthGuard implements CanActivateChild {
      constructor(
        private authService: AuthService,
        private logger: NGXLogger,
        private router: Router
      ) {}
    
      canActivateChild(
        next: ActivatedRouteSnapshot,
        state: RouterStateSnapshot): Observable<boolean | UrlTree> {
    
        return this.authService.isLoggedIn().pipe(
          map(isLoggedIn => {
            if (!isLoggedIn) {
              return this.router.parseUrl('/login');
            }
    
            return true;
          })
        );
      }
    }
    

    Big thanks to Angular In Depth for the explanation!

    Reply

Leave a Comment