Setting Up HTTP Interceptors in Angular

 Setting Up HTTP Interceptors in Angular


1. Setting Up HTTP Interceptors in Angular

Step 1: Create the Global Error Handling Interceptor

First, create an interceptor for handling global errors.

ng generate service interceptors/global-error

Now, update the global-error.interceptor.ts file:

// global-error.interceptor.ts

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

import { HttpEvent, HttpHandler, HttpInterceptor, HttpErrorResponse } from '@angular/common/http';

import { Observable } from 'rxjs';

import { catchError } from 'rxjs/operators';

import { throwError } from 'rxjs';

import { ToastrService } from 'ngx-toastr'; // Import Toastr for error notifications

 

@Injectable()

export class GlobalErrorInterceptor implements HttpInterceptor {

 

  constructor(private toastr: ToastrService) {}

 

  intercept(req: any, next: HttpHandler): Observable<HttpEvent<any>> {

    return next.handle(req).pipe(

      catchError((error: HttpErrorResponse) => {

        let errorMessage = 'An unknown error occurred!';

       

        if (error.error instanceof ErrorEvent) {

          // Client-side error

          errorMessage = `Error: ${error.error.message}`;

        } else {

          // Server-side error

          if (error.status === 0) {

            errorMessage = 'No internet connection!';

          } else if (error.status === 400) {

            errorMessage = 'Bad Request!';

          } else if (error.status === 401) {

            errorMessage = 'Unauthorized! Please log in.';

          } else if (error.status === 500) {

            errorMessage = 'Server error. Please try again later.';

          }

        }

 

        // Show toastr error message

        this.toastr.error(errorMessage, 'Error');

        return throwError(() => new Error(errorMessage));

      })

    );

  }

}

Step 2: Create the JWT Token Interceptor

Next, create an interceptor that adds a JWT token to HTTP requests.

ng generate service interceptors/jwt-interceptor

Now, update the jwt-interceptor.ts file:

// jwt-interceptor.ts

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

import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';

import { Observable } from 'rxjs';

import { AuthService } from '../services/auth.service'; // AuthService to get JWT token

 

@Injectable()

export class JwtInterceptor implements HttpInterceptor {

 

  constructor(private authService: AuthService) {}

 

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    const token = this.authService.getToken(); // Assuming AuthService has getToken() method to get the JWT

 

    // If there is a token, add it to the Authorization header

    if (token) {

      const clonedRequest = req.clone({

        setHeaders: {

          Authorization: `Bearer ${token}`

        }

      });

      return next.handle(clonedRequest);

    }

 

    // If no token, just forward the request

    return next.handle(req);

  }

}

In the above code, the JwtInterceptor adds a JWT token to the Authorization header of every HTTP request if the token exists.

Step 3: Update the AuthService

For the JWT interceptor to work, you need an AuthService that manages the authentication token. Here’s an example of how the AuthService might look.

// auth.service.ts

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

 

@Injectable({

  providedIn: 'root'

})

export class AuthService {

 

  constructor() { }

 

  // Mock method to get the JWT token (replace with real implementation)

  getToken(): string | null {

    return localStorage.getItem('auth_token'); // Replace with your token storage mechanism

  }

 

  // Mock method to set the JWT token (replace with real implementation)

  setToken(token: string): void {

    localStorage.setItem('auth_token', token);

  }

 

  // Mock method to clear the JWT token (replace with real implementation)

  clearToken(): void {

    localStorage.removeItem('auth_token');

  }

}

This AuthService is where you'll store and retrieve the JWT token (e.g., from localStorage or sessionStorage).

Step 4: Register the Interceptors in app.module.ts

Now that we’ve created the interceptors, we need to register them in the Angular application.

Update app.module.ts to include the interceptors:

// app.module.ts

import { NgModule } from '@angular/core';

import { BrowserModule } from '@angular/platform-browser';

import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';

import { ToastrModule } from 'ngx-toastr'; // Import toastr module

import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

 

import { AppComponent } from './app.component';

import { CrudComponent } from './crud/crud.component';

import { GlobalErrorInterceptor } from './interceptors/global-error.interceptor';

import { JwtInterceptor } from './interceptors/jwt-interceptor';

import { AuthService } from './services/auth.service';

 

@NgModule({

  declarations: [

    AppComponent,

    CrudComponent

  ],

  imports: [

    BrowserModule,

    HttpClientModule,

    BrowserAnimationsModule,

    ToastrModule.forRoot() // ToastrModule

  ],

  providers: [

    AuthService, // Provide AuthService for JwtInterceptor

    {

      provide: HTTP_INTERCEPTORS,

      useClass: JwtInterceptor,

      multi: true // Ensure multiple interceptors can be used

    },

    {

      provide: HTTP_INTERCEPTORS,

      useClass: GlobalErrorInterceptor,

      multi: true // Ensure multiple interceptors can be used

    }

  ],

  bootstrap: [AppComponent]

})

export class AppModule { }

Here, we are adding both JwtInterceptor and GlobalErrorInterceptor to the HTTP_INTERCEPTORS array in the providers section of the Angular module. The multi: true option ensures that multiple interceptors can be chained.

2. Final Thoughts

  • JWT Interceptor: This interceptor will check for the JWT token in the AuthService, and if it exists, it attaches it to the Authorization header of all outgoing HTTP requests.
  • Global Error Interceptor: This interceptor will catch all errors in your HTTP responses globally, and you can display error messages using Toastr or handle them accordingly.

Now, your Angular app is set up with:

  1. Global error handling using the GlobalErrorInterceptor.
  2. JWT token handling using the JwtInterceptor.

Both interceptors will handle every HTTP request and response automatically, allowing for centralized management of authentication and error handling across your app.

 

To implement the discussed functionality in your Dotnet Core Web API, we can create endpoints that correspond to the actions in the Angular app, as well as provide JWT authentication and global error handling. Below is a step-by-step guide to implement this functionality in your .NET Core Web API:

1. Setup JWT Authentication in .NET Core

a) Install the necessary NuGet packages:

First, ensure you have the required packages for JWT authentication in your .NET Core project:

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer

dotnet add package System.IdentityModel.Tokens.Jwt

b) Configure JWT Authentication:

In Startup.cs or Program.cs (depending on your project version), configure JWT authentication.

public void ConfigureServices(IServiceCollection services)

{

    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)

        .AddJwtBearer(options =>

        {

            options.TokenValidationParameters = new TokenValidationParameters

            {

                ValidateIssuer = true,

                ValidateAudience = true,

                ValidateLifetime = true,

                ValidateIssuerSigningKey = true,

                ValidIssuer = Configuration["Jwt:Issuer"],

                ValidAudience = Configuration["Jwt:Audience"],

                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:SecretKey"]))

            };

        });

 

    services.AddControllers();

}

c) Configure JWT Token Generation:

Create a utility to generate JWT tokens.

public class JwtService

{

    private readonly string _secretKey;

    private readonly string _issuer;

    private readonly string _audience;

 

    public JwtService(IConfiguration configuration)

    {

        _secretKey = configuration["Jwt:SecretKey"];

        _issuer = configuration["Jwt:Issuer"];

        _audience = configuration["Jwt:Audience"];

    }

 

    public string GenerateToken(string username)

    {

        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_secretKey));

        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

 

        var claims = new[] {

            new Claim(ClaimTypes.Name, username)

        };

 

        var token = new JwtSecurityToken(

            _issuer,

            _audience,

            claims,

            expires: DateTime.Now.AddHours(1),

            signingCredentials: credentials

        );

 

        return new JwtSecurityTokenHandler().WriteToken(token);

    }

}

d) Add JWT Service to Dependency Injection:

In Startup.cs or Program.cs, register the JWT service.

services.AddSingleton<JwtService>();

e) Create a Login Endpoint:

Create an endpoint to authenticate and issue JWT tokens.

[HttpPost("login")]

public IActionResult Login([FromBody] LoginRequest model)

{

    // Example logic to authenticate user (this would usually involve checking a database)

    if (model.Username == "test" && model.Password == "password")

    {

        var token = _jwtService.GenerateToken(model.Username);

        return Ok(new { token });

    }

 

    return Unauthorized("Invalid credentials");

}

2. Implement Global Error Handling

In .NET Core, you can implement global error handling using middleware or by using exception filters.

a) Create a Global Exception Middleware:

Create a middleware to catch all unhandled exceptions globally and send an appropriate response.

public class GlobalExceptionMiddleware

{

    private readonly RequestDelegate _next;

 

    public GlobalExceptionMiddleware(RequestDelegate next)

    {

        _next = next;

    }

 

    public async Task InvokeAsync(HttpContext httpContext)

    {

        try

        {

            await _next(httpContext);

        }

        catch (Exception ex)

        {

            await HandleExceptionAsync(httpContext, ex);

        }

    }

 

    private Task HandleExceptionAsync(HttpContext context, Exception exception)

    {

        context.Response.ContentType = "application/json";

        context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

 

        var response = new { message = exception.Message, details = exception.StackTrace };

 

        return context.Response.WriteAsync(JsonConvert.SerializeObject(response));

    }

}

b) Register the Middleware:

In Startup.cs or Program.cs, register the middleware.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)

{

    app.UseMiddleware<GlobalExceptionMiddleware>();

 

    // Other middlewares like routing, authentication, etc.

}

3. Secure API Endpoints with JWT Authentication

Ensure that the necessary API endpoints are protected using JWT authentication by adding the [Authorize] attribute to those controllers or actions.

[Authorize]

[ApiController]

[Route("api/[controller]")]

public class ItemsController : ControllerBase

{

    private readonly IItemService _itemService;

 

    public ItemsController(IItemService itemService)

    {

        _itemService = itemService;

    }

 

    [HttpGet]

    public IActionResult GetItems()

    {

        var items = _itemService.GetItems();

        return Ok(items);

    }

 

    [HttpPost]

    public IActionResult CreateItem([FromBody] Item item)

    {

        var createdItem = _itemService.CreateItem(item);

        return CreatedAtAction(nameof(GetItems), new { id = createdItem.Id }, createdItem);

    }

 

    [HttpPut("{id}")]

    public IActionResult UpdateItem(int id, [FromBody] Item item)

    {

        var updatedItem = _itemService.UpdateItem(id, item);

        return Ok(updatedItem);

    }

 

    [HttpDelete("{id}")]

    public IActionResult DeleteItem(int id)

    {

        _itemService.DeleteItem(id);

        return NoContent();

    }

}

4. Add CORS Configuration (If Necessary)

If your Angular frontend is hosted separately, you may need to allow cross-origin requests by configuring CORS in Startup.cs:

public void ConfigureServices(IServiceCollection services)

{

    services.AddCors(options =>

    {

        options.AddPolicy("AllowAllOrigins", builder =>

        {

            builder.AllowAnyOrigin()

                   .AllowAnyMethod()

                   .AllowAnyHeader();

        });

    });

 

    services.AddControllers();

}

And register it in the Configure method:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

{

    app.UseCors("AllowAllOrigins");

 

    // Other middleware

}

5. Summary

In your .NET Core Web API:

  • JWT Authentication: Protect your API with JWT tokens.
  • Global Error Handling: Create middleware to handle unexpected exceptions.
  • Secure Endpoints: Use the [Authorize] attribute on controllers and actions that need to be secured.
  • CORS: If you're using a separate frontend, make sure CORS is configured correctly.

This setup allows your Angular app to interact with the API via HTTP, with JWT-based authentication and global error handling.

 

Comments

Popular posts from this blog

Multiline to singleline IN C# - CODING

EF Core interview questions for beginners

EF Core interview questions for experienced