javascriptangularscadalts

Authentication service always return false


My authentication service works almost fine, but the problem is that I'm getting the information if user is logged or not from an asynchro http request.

ActivationGuard.ts

import {Injectable} from '@angular/core';
import {Router, RouterStateSnapshot, ActivatedRouteSnapshot} from '@angular/router';
import {Observable} from 'rxjs/Observable';
import {UserAuthenticationService} from './UserAuthenticationService';

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

@Injectable()
export class ActivationGuard implements CanActivate {

    constructor(private router: Router, private userService: UserAuthenticationService) {
    }

    public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {

        if (this.userService.isUserAuthenticated == false) {
            this.router.navigate(['/']);
            return false;
        }
        return true;
    }
}

UserAuthenticationService.ts

import {Injectable, OnInit} from '@angular/core';
import {Http} from '@angular/http';

@Injectable()
export class UserAuthenticationService implements OnInit {
    isUserAuthenticated: boolean = false;
    username: string = 'admin';

    constructor(private http: Http) {}


    ngOnInit(){
        this.http.get(`http://localhost/api/auth/isLogged/${this.username}`)

            .subscribe(res => {
                    this.isUserAuthenticated = res.json();
                },
                err => {
                    console.error('An error occured.' + err);
                });
    }


}

Everytime I'm getting false (it doesn't allow me to enter the app even if I'm logged).

But if I change the isUserAuthenticated: boolean = false; line from the UserAuthenticationService.ts file to true - it never kicks me out - isUserAuthenticated is always true.

May it be caused by the http request and it's asynchro nature? Or maybe there's a better way to deal with it?

Looking forward for any help. Thank you.


Solution

  • You are able to return not only boolean but Observable or Promise in canActivate method:

    ActivationGuard.ts

    import { Injectable } from '@angular/core';
    import {Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot} from '@angular/router';
    import {Observable} from "rxjs/Observable";
    import {UserAuthenticationService} from './UserAuthenticationService';
    
    @Injectable()
    export class ActivationGuard implements CanActivate {
    
        constructor(private router: Router, private userService: UserAuthenticationService) {
        }
    
    
        canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
            return this.userService.isUserAuthenticated
                .do(success => {
                    if (!success) {
                        this.router.navigate(['/']);
                    }
                });
        }
    }
    

    Also let's make isUserAuthenticated an observable, so ActivationGuard will be subscribing on this pipe:

    UserAuthenticationService.ts

    import {Injectable} from '@angular/core';
    import {Http} from '@angular/http';
    import {Observable} from "rxjs/Observable";
    
    @Injectable()
    export class UserAuthenticationService {
        public isUserAuthenticated:Observable<boolean>;
        username: string = 'admin';
    
        constructor(private http: Http) {
            this.isUserAuthenticated = this.http.get(`http://localhost/api/auth/isLogged/${this.username}`)
                .map(res => res.json())
                .share();
        }
    }