1

I have been searching in order to avoid duplicated posting etc. and did give some solutions a try, but was not successful to fix the issue.

I use canActivate to protect a dashboard and it works fine except that it always returning false so that I can never access the protected routers.

I don't get any error or something similar so that I can localize and fix. the isAuthenticated is always being set to false and doesn't get the result of the function: setAuthenticated() which is changing it to: true.

Any idea please?

auth.service.ts:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable()
export class AuthService {

    public isAuthenticated = false;

    constructor(private http: HttpClient) {
    }

    setUserLoggedIn() {
        this.isAuthenticated = true;
    }

    getUserLoggedIn() {
        return this.isAuthenticated;
    }

    public setAuthenticated() {

        this.http
            .get<any>(url, {withCredentials: true, observe: 'response'})
            .subscribe(
                (res) => {
                    console.log('Status: Authenticated: ' + res.headers.get('status') );
                    if ( res.headers.get('status') === '200') {
                        this.setUserLoggedIn();
                    }
                },
                err => {});
    }
}

authguard.guard.ts:

import { Injectable } from '@angular/core';
import { CanActivate,
         ActivatedRouteSnapshot,
         RouterStateSnapshot,
         Router,
         ActivatedRoute} from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { HttpClient } from '@angular/common/http';
import { AuthService } from './service/auth.service';


@Injectable()
export class AuthguardGuard implements CanActivate {
    constructor(
        private user: AuthService,
        public router: Router,
        private http: HttpClient,
        private activatedRoute: ActivatedRoute) {
    }

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

        if ( !this.user.isAuthenticated ) {
            console.log('Not authenticated!');
            this.router.navigate(['userLogin']);
            return false;
        }
        return true;
    }
}
k.vincent
  • 3,743
  • 8
  • 37
  • 74
  • Look when is the method "setAuthenticated" is getting called. If you call this method, it gets the response after some time (network call) till that time the value of the isAuthenticated will be false – Basavaraj Bhusani Mar 20 '18 at 19:21
  • Exactly! and it this is where I'am struggling... how to force canActivate to wait till the `setAuthenticated ` is being invoked and the new value of `isAuthenticated ` is set to true. – k.vincent Mar 20 '18 at 19:25
  • the value start on false in the auth service, do you ever change to true? – Jota.Toledo Mar 20 '18 at 19:32

1 Answers1

1

The best way is to use Observable in Auth-Guard. Like below:

In auth.service.ts, change "setAuthenticated" method as below.

public setAuthenticated() {
// YOU SHOULD SET "isAuthenticated" value to FALSE when the session is over.
if (this.isAuthenticated === true) {
    return Observable.of(true);
} else {
    return this.http.get<any>(url, {withCredentials: true, observe: 'response'})
      .map((res) => {
        if ( res.status === 200) {
             this.isAuthenticated = true;
             return true;
        } else {
            this.isAuthenticated = false;
            console.log('Not authenticated!');
            this.router.navigate(['userLogin']);
            return false;
        }
    });
}
}

authguard.guard.ts:

// All imports
@Injectable()
export class AuthguardGuard implements CanActivate {
constructor(
    private user: AuthService,
    public router: Router,
    private http: HttpClient,
    private activatedRoute: ActivatedRoute) {
}

canActivate(): Observable<boolean> {
   return this.user.setAuthenticated()
     .map((res) => {
        if ( res === true) {
             return true;
        } else {
            console.log('Not authenticated!');
            this.router.navigate(['userLogin']);
            return false;
        }
    });
  }
}
Basavaraj Bhusani
  • 5,375
  • 2
  • 16
  • 24
  • I'll give tit a try... one question pls. for what is the `params `? – k.vincent Mar 20 '18 at 19:36
  • @k.vincent , Params include any parameters you want to send to that method. I have edited the answer, check it – Basavaraj Bhusani Mar 20 '18 at 19:41
  • Unfortunately always going to login ;-( – k.vincent Mar 20 '18 at 19:49
  • Put console logs and trace the code in dev mode. Make sure `res.headers.get('status)` returns the value `'200'` – Basavaraj Bhusani Mar 20 '18 at 19:53
  • if I add: `alert(res.headers.get('status'));` in the service after after: `return this._http.get(environment.urlUserInfo, {withCredentials: true, observe: 'response'}) .map((res) => {...`, I get `null`. But after the page is loaded I see that the header status is `200`and response is fine – k.vincent Mar 20 '18 at 19:58
  • @BasavarajBhusani: I think the moment is the response still not available.. that's why `null` – k.vincent Mar 20 '18 at 20:01
  • You should add alerts/logs after `.map((res) => { console.log(res); }`. check the values. – Basavaraj Bhusani Mar 20 '18 at 20:04
  • If I add this in service after `.map(...)` `console.log(JSON.stringify (res) + 'header: ' + res.headers.get('status'));` it gives me the whole response where I can see headers with status `200`, but then it's `null`. if I add this after `.map(...)` `console.log( 'in Guard ' + JSON.stringify (res) );` in authguard, it gives me: `false` – k.vincent Mar 20 '18 at 20:12
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/167208/discussion-between-k-vincent-and-basavaraj-bhusani). – k.vincent Mar 20 '18 at 20:14
  • @BasavarajBhusani I'm having similar issue, can you please take a look? https://stackoverflow.com/questions/74424097/why-angular-guards-can-activate-always-returns-false – Ali Nov 13 '22 at 19:41