Each time the Angular Service is called, it undergoes a reset process

For my Angular web project, I have implemented an AuthenticationGuard and an AuthenticationService to manage security.

These components are from a separate branch of the project that is functioning perfectly.

This is how the process should occur:

  1. Go to 'auth/login'
  2. User enters credentials
  3. AuthService requests a Bearer Token from the backend webApi
  4. Backend sends back the token
  5. AuthService sets its 'isLoggedIn' variable to true;
  6. AuthService uses the router to navigate to '/home'
  7. AuthGuard verifies authentication by checking AuthService's 'isLoggedIn' state

The issue arises when AuthGuard accesses AuthService: AuthService consistently returns 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;
                }
            });
    }
}

Answer №1

It appears that without examining your module definitions, it seems like AuthService may not be implemented as a core service (a Singleton), causing each module to have its own instance and manage its isLoggedIn flag independently.

In Angular, making a service a singleton requires it to be provided by the root module injector. To achieve this, follow these steps:

import { NgModule } from '@angular/core';
import { CommonModule, ModuleWithProviders } from '@angular/common';
import { AuthService, AuthGuard } from './services/index';

@NgModule({
  imports: [
    CommonModule,
    ModuleWithProviders
  ]
})
export class SharedModule {

  static forRoot(): ModuleWithProviders {
    return {
      ngModule: SharedModule,
      providers: [
        AuthService,
        AuthGuard
      ]
    };
  }

}

Then utilize the forRoot method when importing SharedModule into the root AppModule.

@NgModule({
  imports: [
    ...
    SharedModule.forRoot(),
    ...
  ],
  ...,
  bootstrap: [AppComponent]
})
export class AppModule { }

Refer to "Configure Core Services" at https://angular.io/docs/ts/latest/guide/ngmodule.html#!#core-for-root for more information.

Answer №2

I encountered a similar issue where the click event on a button element was causing the entire form to be submitted in Chrome. This happened because Chrome treats a button click as a submit action if no type attribute is specified for the button.

To resolve this, I added the type="button" tag to the login button in the HTML code.

More information can be found here

Answer №3

Dependencies are unique instances within the context of an injector.

Although, Angular DI operates on a hierarchical injection system, permitting nested injectors to generate their own service objects. For further details, refer to Hierarchical Injectors.
Source

It's crucial to verify where you specify the `provide` for your services.

Review all your modules and check the `providers` section in each one.
If multiple instances exist - every module will have its unique instance of the service.

I encountered a similar issue myself when I unintentionally added `AuthService` to AppModule while forgetting to remove it from AuthModule, resulting in the login page (within the auth module) having another separate instance of the service.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

No errors encountered during compilation for undefined interface object types

Hey there, I'm currently exploring the Vue composition API along with Typescript. I'm facing an issue where I am not receiving any errors when an interface does not align with the specified types for that interface. Although my IDE provides aut ...

Exploring the world of unit testing in aws-cdk using TypeScript

Being a newcomer to aws-cdk, I have recently put together a stack consisting of a kinesis firehose, elastic search, lambda, S3 bucket, and various roles as needed. Now, my next step is to test my code locally. While I found some sample codes, they did not ...

What are some ways I can incorporate PrimeNG components into my Ionic 4 project?

Exploring the integration of PrimeNG components in an Ionic 4 application is my current project. The initial steps I took included creating a blank Ionic 4 app: ionic start myApp blank Afterwards, I proceeded to download PrimeNG into the project: npm ...

Encountered an issue when trying to convert JSON into an array and loop through it in an HTML file using a

Currently, I am working on a project involving Angular where I am retrieving data from an API through a GET call. Specifically, one column's data is being converted from JSON to an array. However, when attempting to iterate over this array in the HTML ...

Indicate a specific type for the Express response

Is there a method to define a specific type for the request object in Express? I was hoping to customize the request object with my own type. One approach I considered was extending the router type to achieve this. Alternatively, is there a way to refactor ...

Retrieve the input value from a Bootstrap Form Input

When using a Bootstrap Form Input to allow the user to enter text, I am wondering how to save that text and use it as a parameter in a function. Below is the HTML snippet I have: <!--Directory Input Form--> <div class="row"> <div class= ...

I am curious if there is a method to obtain the component's logic or the value of an element's style within animation metadata in Angular

Is there a way to determine the height of a dynamically created component from a recursive tree without using the tree inside metadata declarations? One possibility is calculating the height inside the *ngStyle directive as shown below: <my-directory [ ...

The array does not yield any values when utilizing Angular CLI

Recently, I created a component that contains an array of strings. Here's the code snippet for reference: import {Component} from '@angular/core'; @Component({ selector: 'app-products-list', templateUrl: './products-list. ...

Ways to transfer data from TypeScript to CSS within Angular 6

Trying to work with ngClass or ngStyle, but I'm struggling with passing the value. Here's my current code: strip.component.ts import { ... } from '@angular/core'; @Component({ selector: 'app-strip', templateUrl: &apo ...

unable to display toolbar in ckeditor5 decoupled document with Angular

Having trouble implementing CKeditor5 decoupled document in Angular-10 and unable to display the toolbar. Component.ts import * as CKeditor from '@ckeditor/ckeditor5-build-decoupled-document'; export class MyComponent { editor = CKeditor } ...

Vue's span function is yielding the promise object

In my Vue component, I am using the function getOrderCount to fetch the number of orders from a specific URL and display it in one of the table columns. <div v-html="getOrderCount(user.orders_url)"></div> async getOrderCount(link) { ...

TSLint throws an error, expecting either an assignment or function call

While running tslint on my angular project, I encountered an error that I am having trouble understanding. The error message is: expected an assignment or function call getInfoPrinting() { this.imprimirService.getInfoPrinting().subscribe( response => ...

Exploring through objects extensively and expanding all their values within Angular

I am in need of searching for a specific value within an object graph. Once this value is found, I want to set the 'expanded' property to true on that particular object, as well as on all containing objects up the object graph. For example, give ...

Solving Angular2 Dependency Issues

I'm curious about Angular 2 and whether there's a way to resolve dependencies without having to use the constructor. In .NET, you can inject dependencies in three ways (constructor, setter, interface-based). Is it possible to do setter injection ...

Angular 2's ng-required directive is used to specify that

I have created a model-driven form in Angular 2, and I need one of the input fields to only show up if a specific checkbox is unchecked. I was able to achieve this using *ngIf directive. Now, my question is how can I make that input field required only whe ...

Utilizing Regular Expressions as a Key for Object Mapping

Currently, I am facing a challenge in mapping objects with keys for easy retrieval. The issue arises when the key can either be a string or a RegExp. Assigning a string as a key is simple, but setting a regex as a key poses a problem. This is how I typica ...

Changing the generic type's constraint type in TypeScript to have more flexibility

I have developed a utility type named DataType that takes in a parameter T restricted to the type keyof MyObject. When the key exists in MyObject, DataType will return the property type from MyObject; otherwise, it will simply return T. interface MyObject ...

Is TypeScript 2.8 Making Type-Safe Reducers Easier?

After reading an insightful article on improving Redux type safety with TypeScript, I decided to simplify my reducer using ReturnType<A[keyof A]> based on the typeof myActionFunction. However, when creating my action types explicitly like this: exp ...

What is the term for specifying a variable's data type using a set of values instead of a traditional type?

Recently, I stumbled upon some code that introduces a class with specific variables defined in an unconventional manner. export class Foo { id: string = "A regular string" bar: '>' | '<' | '=' | '<=' | ...

The Angular2 Observable fails to be activated by the async pipe

Take a look at this simple code snippet using angular2/rxjs/typescript public rooms: Observable<Room[]>; constructor ( ... ) { this.rooms = this.inspectShipSubject .do(() => console.log('foo')) .switchMap(shi ...