Home > Net >  Why Angular guard is running before ngOnInit?
Why Angular guard is running before ngOnInit?

Time:09-11

I have checkAuth function in ngOnInit in app.component.ts which checks localStorage for token and if token is valid authService logs you in.

Also, I have AuthGuard in /profile route which checks if you logged in.

If I click the link in the navbar this works great, but if I go to link directly authGuard working before my checkAuth function and returns false.

Where do I need to place my checkAuth function to make it work correctly? Or maybe I need to change something in AuthGuard or in app.component

Here is AuthGuard code

@Injectable({
  providedIn:'root'
})
export class AuthGuard implements CanActivate, CanActivateChild {

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

  canActivate(route:ActivatedRouteSnapshot, state:RouterStateSnapshot):Observable<boolean>{
    console.log(this.auth.isAuth)
    console.log(this.auth.isLoggedIn())
    if (this.auth.isLoggedIn()){
      return of(true)
    } else {
      this.router.navigate(['/login'])
      return of(false)
    }
  }

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

app.component

ngOnInit() {
    if (localStorage.getItem('token')){
      this.auth.checkAuth().subscribe(
        (data) => {
          console.log(data)
          console.log(this.auth.isAuth)
        }
      )
    }
  }

and checkAuth in AuthService

checkAuth():Observable<UserDto>{
     return this.http.get<UserDto>(`/api/user/refresh`, {withCredentials:true, observe:'body', responseType:'json'})
        .pipe(
          tap(
            (data) => {
              localStorage.setItem('token', data.accessToken)
              this.setAuth(true)
              this.setUser(data.user)
            },
            (error) => {
              console.log(error)
            }
          )
        )
  }

CodePudding user response:

If you want checkAuth to run before the guard, you have to make it a guard as well, and use it before the guard that you already have. E.g: canActivate: [CheckAuthGuard, AuthGuard].

This is what's going on right now:

First scenario - accessing /profile by clicking in the navbar

  1. You access the application's root component
  2. Whatever guards you have on the root route run
  3. The root component is initialized and AppComponent.ngOnInit() runs, thus running checkAuth()
  4. You click the link in the navbar to go the /profile route
  5. Guards for the profile route are run

Second scenario - accessing /profile by visiting the URL directly

  1. You access the application's root component, but this time it is routed to the /profile route
  2. Whatever guards you have on the profile route run
  3. The root component and it's child are initialized, running their ngOnInit() methods

See? In the second scenario, the guard runs before ngOnInit and checkAuth. I advise you to put some console.log calls on your app, so you can more easily see the order in which things are happening.

Basically this is it, guards run before the component is rendered, so you should keep that in mind. Extract your checkAuth call to a guard and you'll be fine.

  • Related