0

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.

Kaysh
  • 83
  • 1
  • 7

1 Answers1

2

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();
    }
}
karser
  • 1,625
  • 2
  • 20
  • 24
  • Thanks, I have followed your each step, but unfortunately it throws me an error when entering the protected component: `Promise rejection. Cannot read property 'do' of undefined`. Do you know why do I receive such error? – Kaysh Apr 28 '17 at 11:42
  • @Kaysh Try to init isUserAuthenticated in constructor instead of ngOnInit. I modified the answer. – karser Apr 28 '17 at 14:55
  • Im amazed how does it work. It's truely amazing. Thank you for it. – Kaysh Apr 28 '17 at 15:34