Search code examples
angularrxjsangular-ui-router

Im using the latest AuthGuard method, its supposed to redirect using router.createUrlTree if user is not logged in but it fails to do so


Im unable to redirect to /user pleas help

here is the AuthGuard where I have subscribed to an authService.authSubStatus that emits a boolean

import { inject, Injectable } from '@angular/core';
import { map, Observable } from 'rxjs';
import {
  ActivatedRouteSnapshot,
  CanActivateChildFn,
  CanActivateFn,
  Router,
  RouterStateSnapshot,
  UrlTree,
} from '@angular/router';
import { AuthDataService } from './authDataService';

@Injectable({ providedIn: 'root' })
export class AuthGuard {
  static authGuardFn: CanActivateFn = (
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean | UrlTree> => {
    const router = inject(Router);
    const authService = inject(AuthDataService);

    return authService.authSubStatus.pipe(
      map((status) => {
        if (status) return true;
        return router.createUrlTree(['/user']);
      })
    );
  };
}

here is the AuthDataService from which only authSubStatus is used as an observer to be subscribed to in AuthGuard


import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { User } from '../Model/userModel';
import { Subject, tap } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class AuthDataService {
  authenticated = false;

  authSubStatus = new Subject<boolean>();

  constructor(private http: HttpClient) {}

  testService() {
    console.log(this);
  }

  //LOG-IN posting basic auth to the backend

  postBasicAuthData(username: string, password: string) {
    console.log(username, password);

    const header = new HttpHeaders();

    const authHeader = header.set(
      'Authorization',
      'Basic ' + window.btoa(username + ':' + password)
    );

    return this.http
      .get<any>('http://localhost:8080/login/LoginUser', {
        headers: authHeader,
        observe: 'response',
        withCredentials: true,
      })
      .pipe(
        tap((responseData) => {
          if (responseData) {
            this.authenticated = true;
            this.authSubStatus.next(this.authenticated);
          }
        })
      );
  }

  //SIGN-UP sign up a new user

  newUserDetailsPost(
    username: string,
    password: string,
    age: number,
    email: string
  ) {
    console.log(username, password, age, email);

    return this.http.post<any>('http://localhost:8080/Sign-up/signup-user', {
      name: username,
      password: password,
      age: age,
      email: email,
    });
  }
}

here is app.routes

import { Routes } from '@angular/router';
import { LoginSignupComponent } from './login-signup/login-signup.component';
import { SuccessComponent } from './success/success.component';
import { AuthGuard } from './Service/authGuardService';

export const routes: Routes = [
  {
    path: '',
    redirectTo: 'user',
    pathMatch: 'full',
  },
  {
    path: 'user',
    component: LoginSignupComponent,
    //login signup routs in lazy mode
    loadChildren: () =>
      import('./login-signup/login-logout.routes').then(
        (mode) => mode.LOGIN_LOGOUT_ROUTS
      ),
  },
  {
    path: 'welcome',
    component: SuccessComponent,
    canActivate: [AuthGuard.authGuardFn],
  },
];

In my AuthGuard service im trying to return an createUrlTree that redirects to /users

    return authService.authSubStatus.pipe(
      map((status) => {
        if (status) return true;
        return router.createUrlTree(['/user']);
      })
    );

but it fails to redirect to '/user' when user is not logged in however when user is logged in it works and the guard shows the welcome page like normal


Solution

  • I'd say that the problem may come from the fact that the authSubStatus is a Subject that holds no default value, it is possible that your guard is just waiting indefinitely for an observable that will never emit any value.

    You may try to replace it with a BehaviourSubject which does hold a default value, this will ensure that even when the user hasn't tried to log in, the guard will still get a value from your AuthDataService and will not stay stuck forever.

    authSubStatus = new BehaviorSubject<boolean>(false);
    

    I've tried it and it seems to work but there may be other problems.