I need to implement a CanActivateFn guard to block non authenticated users in an Angular project.

I tried different approaches and shaped this guard so far.

import { inject } from '@angular/core';
import {
  ActivatedRouteSnapshot,
  CanActivateFn,
  Router,
  RouterStateSnapshot,
  UrlTree,
} from '@angular/router';
import { IUser } from '../model/user.model';

export const authGuard: CanActivateFn = (
  route: ActivatedRouteSnapshot,
  state: RouterStateSnapshot
): Promise<boolean | UrlTree> | boolean | UrlTree => {
  let isAuthenticated = false;

  let baseUrl: string = 'https://localhost:44411/';

  let currentUser = <IUser>{};

  // I need to get user info syncronusly
  fetch(baseUrl + 'Account/GetUser')
    .then((response) => response.json())
    .then((json) => {
      currentUser = jsonas IUser;
    })
    .catch((error) => {
      console.error('There was an error to get user information.');
    });

  isAuthenticated = currentUser.isAuthenticated;

  //  Redirects to login route
  const isAnonymous = !isAuthenticated;

  if (isAnonymous) {
    return inject(Router).createUrlTree(['/', 'login']);
  }

  return isAuthenticated;
};

The issue is that I need to find a way to get user data synchronously to be able to do validation based on a user data.

Please suggest how to achieve the requirement or suggest a different approach. Note: I need to use fetch to get user data.

1

There are 1 answers

4
Naren Murali On BEST ANSWER

Convert the promise to an observable, then validate the logic on a map if error catch using catchError present then navigate.

import { inject } from '@angular/core';
import {
  ActivatedRouteSnapshot,
  CanActivateFn,
  Router,
  RouterStateSnapshot,
  UrlTree,
} from '@angular/router';
import { IUser } from '../model/user.model';
import { lastValueFrom } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
import { HttpClient } from '@angular/common/http';

export const authGuard: CanActivateFn = (
  route: ActivatedRouteSnapshot,
  state: RouterStateSnapshot
): Promise<boolean | UrlTree> | boolean | UrlTree => {
  let baseUrl: string = 'https://localhost:44411/';
  // I need to get user info syncronusly
  return lastValueFrom(
    inject(HttpClient).get(baseUrl + 'Account/GetUser')
  ).pipe(
    map((currentUser: any) => {
      return !currentUser.isAuthenticated
        ? inject(Router).navigate(['login'])
        : false;
    }),
    catchError(() => inject(Router).navigate(['login']))
  );
};

using fetch

import { inject } from '@angular/core';
import {
  ActivatedRouteSnapshot,
  CanActivateFn,
  Router,
  RouterStateSnapshot,
  UrlTree,
} from '@angular/router';
import { IUser } from '../model/user.model';
import { lastValueFrom } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
import { HttpClient } from '@angular/common/http';

export const authGuard: CanActivateFn = (
  route: ActivatedRouteSnapshot,
  state: RouterStateSnapshot
): Promise<boolean | UrlTree> | boolean | UrlTree => {
  let baseUrl: string = 'https://localhost:44411/';
  // I need to get user info syncronusly
  return lastValueFrom(fetch(baseUrl + 'Account/GetUser')
.then((response) => response.json())).pipe(
    map((currentUser: any) => {
      return !currentUser.isAuthenticated
        ? inject(Router).navigate(['login'])
        : false;
    }),
    catchError(() => inject(Router).navigate(['login']))
  );
};