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:
- Global
error handling using the GlobalErrorInterceptor.
- 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
Post a Comment