How to check if a user is authenticated to acess certain path (MEAN STACK)

Viewed 104

So I am learning MEAN stack, and I am trying to do authentication, I am using passport-local, express-session, passport-mongoose, I dont know if this is the way you do it or there is a better way, I have a get on my node that checks if the user is authenticated.

exports.isLoggedIn = (req, res) => {
    if (req.isAuthenticated()) {
        res.send(true);
    } else {
        res.send(false);
    }
}

on angular I am making a auth service with the http get in this way

isLoggedIn(): Observable<boolean> {
    return this.httpClient.get<boolean>(this.url + '/isLoggedIn', this.httpOptions).pipe(
      retry(2),
      catchError(this.handleError))
  }

and now my problem, when, a user try to acess a certain path, let's say '/profile', I want to use this to check if the user is authenticated or not, so in the angular guard I am doing this

isLoggedIn: boolean;

canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean> | boolean {  

    this.auth.isLoggedIn().subscribe((isLoggedIn: boolean) =>  {         
      this.isLoggedIn = isLoggedIn;       
    }); 

    return this.isLoggedIn;

   }  

the problem I am facing, I think, is that the http is going asyncronous and the canActivate on guard is syncronous, so When I run this for the first time I got undefinied, and the second time returns the true and false as espected but It is from the previous run, so If the user logout he still can acess the '/profile' path. I tried some ways, all failed, and I dont know if it is supposed to be done this way.

1 Answers

Lets divide your question in two parts

  1. You have other ways, more or less same than usage of passport library. so it is good enough, no harm in that.

  2. At Frontend :

The guard might return its boolean answer synchronously. But in many cases, the guard can't produce an answer synchronously. The guard could ask the user a question, save changes to the server, or fetch fresh data. These are all asynchronous operations.

Accordingly, a routing guard can return an Observable or a Promise and the router will wait for the observable to 'resolve' to true or false.

Referred from : https://angular.io/guide/router#milestone-5-route-guards

So considering your subscription in your component, you need to return your observable, something like this

return this.auth.isLoggedIn()

without subscribing. and optionally make the changes in your service to return boolean value there itself. something like

isLoggedIn(): Observable < boolean > {
    return this.httpClient.get < boolean > (this.url + '/isLoggedIn', this.httpOptions)
    .pipe(retry(2), tap(val => this.isLoggedIn = true), catchError(this.handleError))
}

For more way to resolve a loggedIn service here is a reference : https://angular.io/guide/router#resolve-pre-fetching-component-data

Hope this helps.

Related