Angular Service is reset on each call of it

Viewed 6077

In my web Angular project I've created an AuthenticationGuard and an AuthenticationService to handle the security.

These files comes from another branch of my project who works perfectly.

Here is how my scripts should works:

  1. Navigate to 'auth/login'
  2. User inputs his credentials
  3. Authservice call the back-end wepApi to get a Bearer Token
  4. Back-end returns the token.
  5. AuthService set his var 'isLoggedIn' to true;
  6. AuthService use to router to navigate to '/home'
  7. AuthGuard check authentication by checking the 'isLoggedIn' of AuthService.

My problem is when AuthGuard access the AuthService : AuthService always return false.

auth.guard.ts

import { Injectable }       from '@angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot,RouterStateSnapshot } from '@angular/router';
import { AuthService }      from './auth.service';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private authService: AuthService, private router: Router) {}

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    let url: string = state.url;

    return this.checkLogin(url);
  }

  checkLogin(url: string): boolean {
    if (this.authService.getIsLoggedIn()) { 
      return true; 
    }

    // Store the attempted URL for redirecting
    this.authService.redirectUrl = url;

    // Navigate to the login page with extras
    this.router.navigate(['/auth/login']);
    return false;
  }
}

auth.service.ts

import { Injectable } from '@angular/core';
import { Router } from '@angular/router';

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/delay';

import { config } from './../shared/smartadmin.config';

import { Http, Headers, RequestOptions, Response } from '@angular/http';
import 'rxjs/add/operator/map'

@Injectable()
export class AuthService {
    private isLoggedIn: boolean = false;

    public redirectUrl: string;

    constructor(private router: Router, private http: Http) {
    }

    public getIsLoggedIn(): boolean {
        console.log("getIsLoggedIn() = " + this.isLoggedIn); // Always returns false
        return this.isLoggedIn;
    }

    public login(username: string, password: string) {
        this.ProcessLogin(username, password)
            .subscribe(result => {
                if (result === true) {
                    console.log("before attribution");
                    console.log("this.isLoggedIn = " + this.isLoggedIn); // returns false
                    this.isLoggedIn = true;
                    console.log("after attribution");
                    console.log("this.isLoggedIn = " + this.isLoggedIn); // returns true
                    this.router.navigate(this.redirectUrl ? [this.redirectUrl] : ['/home']);
                } else {
                    this.logout();
                }
            });
    }


    public logout(): void {
        localStorage.removeItem('oAuthToken');
        this.isLoggedIn = false;
    }

    private ProcessLogin(username: string, password: string): Observable<boolean> {

        let headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' });
        let options = new RequestOptions({ headers: headers });
        let body = 'grant_type=password&username=' + encodeURIComponent(username) + '&password=' + encodeURIComponent(password);

        let endpoint = config.API_ENDPOINT + 'token';

        return this.http.post(endpoint, body, options)
            .map((response: Response) => {
                // login successful if there's a jwt token in the response
                let token = response.json() && response.json().access_token;
                if (token) {
                    localStorage.setItem('oAuthToken', token);

                    // return true to indicate successful login
                    return true;
                } else {
                    localStorage.removeItem('oAuthToken');
                    // return false to indicate failed login
                    return false;
                }
            });
    }
}

3 Answers

Dependencies are singletons within the scope of an injector.

However, Angular DI is a hierarchical injection system, which means that nested injectors can create their own service instances. For more information, see Hierarchical Injectors.
Source

Just double check where you provide your service.

List your modules and inspect providers section in each.
If there are more than one instance - each module will provide its own instance of service.

I had a same issue and found I add AuthService to AppModule and forget to remove it from AuthModule, so login page(in the auth module) had other instance of it.

Related