Ofir Sasson
Ofir Sasson

Reputation: 671

Angular 6: Guard on all routes is not working

I'm trying to make the frontend secured by only letting certain Id's getting access. I want that If someone try to enter any route except for /login/:id, he'll get page-not-found if he didn't logged already, but it's not working.

These are my routing table and guard:

EDIT: I solved the problem and update the code:

app-routing.module.ts

// Routing array - set routes to each html page
const appRoutes: Routes = [{
    path: 'login/:id',
    canActivate: [AuthGuard],
    children: []
  },
  {
    path: '',
    canActivate: [AuthGuard],
    canActivateChild: [AuthGuard],
    children: [{
        path: '',
        redirectTo: '/courses',
        pathMatch: 'full'
      },
      {
        path: 'courses',
        component: CourseListComponent,
        pathMatch: 'full'
      },
      {
        path: 'courses/:courseId',
        component: CourseDetailComponent,
        pathMatch: 'full'
      },
      {
        path: 'courses/:courseId/unit/:unitId',
        component: CoursePlayComponent,
        children: [{
            path: '',
            component: CourseListComponent
          },
          {
            path: 'lesson/:lessonId',
            component: CourseLessonComponent,
            data: {
              type: 'lesson'
            }
          },
          {
            path: 'quiz/:quizId',
            component: CourseQuizComponent,
            data: {
              type: 'quiz'
            }
          }
        ]
      }
    ]
  },
  {
    path: '**',
    component: PageNotFoundComponent,
    pathMatch: 'full'
  }
];

auth.guard.ts

canActivate(route: ActivatedRouteSnapshot, state:
    RouterStateSnapshot): boolean |
  Observable<boolean> | Promise<boolean> {
    // save the id from route snapshot
    const id = +route.params.id;

    // if you try to logging with id
    if (id) {
      this.authUserService.login(id);

      // if there was error - return false
      if (this.authUserService.errorMessage) {
        this.router.navigate(["/page_not_found"]);
        return false;
      }

      // there wasn't any errors - redirectTo courses and
      // continue
      else {
        this.router.navigate(["courses"]);
        return true;
      }
    }

    // if you already logged and just navigate between pages
    else if (this.authUserService.isLoggedIn())
      return true;

    else {
      this.router.navigate(["/page_not_found"]);
      return false;
    }
  }

canActivateChild(route: ActivatedRouteSnapshot, state:
    RouterStateSnapshot): boolean |
  Observable<boolean> | Promise<boolean> {
    return this.canActivate(route, state);
  }

auth-user.service.ts

export class AuthUserService implements OnDestroy {

  private user: IUser;
  public errorMessage: string;
  isLoginSubject = new BehaviorSubject<boolean>(this.hasToken());

  constructor(private userService: UserService) {}

  // store the session and call http get
  login(id: number) {
    this.userService.getUser(id).subscribe(
      user => {
        this.user = user;
        localStorage.setItem('user', JSON.stringify(this.user));

        localStorage.setItem('token', 'JWT');
        this.isLoginSubject.next(true);
      },
      error => this.errorMessage = <any>error
    );
  }

  // if we have token the user is loggedIn
  // @returns {boolean}
  private hasToken(): boolean {
    return !!localStorage.getItem('token');
  }

  // @returns {Observable<T>}
  isLoggedIn(): Observable<boolean> {
    return this.isLoginSubject.asObservable();
  }

  // clear sessions when closing the window
  logout() {
    localStorage.removeItem('user');
    localStorage.removeItem('token');
    this.isLoginSubject.next(false);
  }

  ngOnDestroy() {
    this.logout();
  }

Upvotes: 2

Views: 2883

Answers (2)

Ofir Sasson
Ofir Sasson

Reputation: 671

So I managed to solve this problem. I added to the route of login/:id children: [] and changed the isLoggedIn to be behaviorSubject so the token won't change after refresh or moving between pages and it worked. I updated the code in the post so everyone could see the solution

Upvotes: 5

Y_Moshe
Y_Moshe

Reputation: 432

change this line:

const id = route.params.id;

to

const id = +route.params.id; // to convert from string to number (it's string from route params)

and one more thing, I'm not sure you should navigate to a page not found like you did ['**']

instead do this: ['/page_not_found']

now I know that 'page_not_found' does not exist in your route but that's the point, because of it, the user will be redirected to a page not found as you wanted

Upvotes: 2

Related Questions