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

Ways to rename a sequelize property following a join operation

I am encountering a problem with sequelize ORM. The data returned after joining has a nested object: { "id": 1, "username": "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4125342e2f26252e282220 ...

No data being displayed or returned from API when using async await

My Ionic 6 + Angular 14 application is currently facing an issue with displaying data retrieved from an API... I have implemented a service to fetch the data from the API and then called this service in the component. The app compiles without any errors a ...

Ways to convert a string into a Date object without using moment.js

I am facing a challenge with 2 dates that are stored in the following format: "04.12.2019, 09:35" // Today "05.12.2019, 12:50" // Another date I need to compare these dates to determine if they have passed or are yet to come. My initial approach was to ...

A versatile generic type infused with dynamic typing and optional parameter flexibility

Looking to develop a function that can accept an optional errorCallback parameter. In cases where the consumer of this function does not provide a callback, I aim to default to a preset handler. The key criteria here are strong typing and utilizing the ret ...

Enhancing collaboration: Seamlessly sharing interface/interface/model files in the integration of

Currently, I am engrossed in developing an application with an Express backend and Typescript whilst utilizing Angular for the frontend. The only snag I'm facing is that I require interface/models files from the backend to be accessible on the fronten ...

Unable to simultaneously execute TypeScript and nodemon

Currently, I am in the process of developing a RESTful API using Node.js, Express, and TypeScript. To facilitate this, I have already installed all the necessary dependencies, including nodemon. In my TypeScript configuration file, I made a modification to ...

Is there a tidier method for coding this JSX?

Is there a way to optimize these function calls for both onGoClick and onNoGoClicked within the SomeForm component? Or is it fine to keep them as they are? <SomeForm onGoClick={() => { cleanupHere(props) }} o ...

Utilizing Typescript and Jest to prevent type errors in mocked functions

When looking to simulate external modules with Jest, the jest.mock() method can be utilized to automatically mock functions within a module. After this, we have the ability to modify and analyze the mocked functions on our simulated module as needed. As ...

Error: The `ngMetadataName` property cannot be accessed because it is undefined or null in Internet Explorer version 10

Encountered an issue in IE 10 that is not present in IE 11: Error: TypeError: Unable to get property 'ngMetadataName' of undefined or null reference The property ngMetadataName can be found in the file vendor.js. This is the content of polyf ...

Convert the existing JavaScript code to TypeScript in order to resolve the implicit error

I'm currently working on my initial React project using Typescript, but I've hit a snag with the code snippet below. An error message is popping up - Parameter 'name' implicitly has an 'any' type.ts(7006) Here is the complet ...

Differences between Pipe and Tap when working with ngxsWhen working with

While experimenting with pipe and subscribe methods, I encountered an issue. When using pipe with tap, nothing gets logged in the console. However, when I switch to using subscribe, it works perfectly. Can you help me figure out what I'm doing wrong? ...

Tips for utilizing the window object in Angular 7

To implement the scrollTo() function of the window object directly, we can use window.scrollTo(0,0). However, when researching how to do this in Angular, I found that many people create a provider as shown below: import {InjectionToken, FactoryProvider} f ...

How to align an image in the center of a circular flex container

I'm facing an issue in my Angular project where I have the following code snippet: onChange(event: any) { var reader = new FileReader(); reader.onload = (event: any) => { this.url = event.target.result; }; reader.readAsData ...

Preventing automatic download and storage of images and videos in an Ionic application

Currently, my chat application allows users to send and receive media such as photos and videos. However, when I open the message page, it automatically downloads and backs up all the media. I am looking to change this functionality on my Ionic page so th ...

Encountering a fresh issue after updating to TS version 4.4.3 while accessing properties of the top "Object may be 'null'."

After upgrading my project to TypeScript 4.4.3 from 3.9.9, I encountered a change in the type declarations for the top property. My project utilizes "strictNullChecks": true, in its configuration file tsconfig.json, and is browser-based rather t ...

Angular material table cell coloring

Here is my current setup: I have an array of objects like this: users : User []; average = 5; compareValue (value){ ...} And I am displaying a table as shown below: <table mat-table [dataSource]="users"> <ng-container matColumnDef= ...

Tips on utilizing array filtering in TypeScript by solely relying on index rather than element callback

When running tslint, I encountered the following error message: https://i.sstatic.net/p2W9D.png Is it possible to filter based on array index without utilizing element callback? Any alternative suggestions would be appreciated. ...

Transferring information to a complex and deeply embedded Angular component

In my current component structure, A includes B, B includes C, and C includes D. I am looking to transfer data from the topmost component (A) to the one at the bottom of the hierarchy (D). Should I utilize data binding in HTML templates, which would requ ...

When there is data present in tsconfig.json, Visual Studio Code does not display errors inline for TypeScript

After creating an empty .tsconfig file (consisting solely of "{ }"), Visual Studio Code immediately displays errors both inline and in the "problems" section. Interestingly, when I populate the tsconfig.json file with data, these errors disappear. Is there ...

The query for PrManagerBundleEntityeb_user is missing the identifier id

In an attempt to delete an object by its ID from the database using the following code in the frontend, I encountered an issue where the link does not function as expected. Here is the error message that I received: The identifier id is missing for a quer ...