๐ How to Secure Your Microservices with JWT Authentication & Ocelot API Gateway? ๐ค๐ Find Out Now
How Secure Are Your Microservices?๐ Add JWT Authentication to Ocelot API Gateway Today!๐
Introduction
We're diving into an essential aspect of securing our microservices architecture: adding JWT authentication to our microservices that use Ocelot as an API gateway. If you've been following along, you know we've already created our microservices and set up Ocelot to redirect all API calls seamlessly. Now, it's time to add an extra layer of security.
Imagine a scenario where your microservices handle sensitive data, such as user information or financial transactions. Without proper authentication, anyone could access your services, potentially leading to data breaches and unauthorized access. This is where JWT (JSON Web Token) authentication comes in. JWTs provide a compact and secure way to transmit information between parties as a JSON object. By adding JWT authentication to our API gateway, we can ensure that only authenticated and authorized users can access our microservices.
In this section, I'll walk you through the step-by-step process of implementing JWT authentication in our Ocelot API gateway, ensuring that each microservice request is authenticated. Let's get started and secure our microservices like a pro!
# Install JWT Package<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="x.x.x" />
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"Authentication": {
"Key": "qa12ed34TgH67JkiYK89LOF4Gf6Hy98Gtyuj7Ki34F",
"Issuer": "http://localhost:7003",
"Audience": "http://localhost:7003"
}
}
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
var key = Encoding.UTF8.GetBytes(builder.Configuration.GetSection("Authentication:Key").Value!);
string issuer = builder.Configuration["Authentication:Issuer"]!;
string audience = builder.Configuration["Authentication:Audience"]!;
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = false,
ValidateIssuerSigningKey = true,
ValidIssuer = issuer,
ValidAudience = audience,
IssuerSigningKey = new SymmetricSecurityKey(key)
};
});
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
{
builder.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin();
});
});
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using System.Collections.Concurrent;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
namespace AuthenticationApi.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class AccountController(IConfiguration config) : ControllerBase
{
private static ConcurrentDictionary<string,string> UserData { get; set; } =
new ConcurrentDictionary<string,string>();
//api/account/login/{email}/{password}
[HttpPost("login/{email}/{password}")]
public async Task<IActionResult> Login(string email, string password)
{
await Task.Delay(500);
var getEmail = UserData!.Keys.Where(e => e.Equals(email)).FirstOrDefault();
if(!string.IsNullOrEmpty(getEmail))
{
UserData.TryGetValue(getEmail, out string? dbPassword);
if (!Equals(dbPassword, password))
return BadRequest("Invalid credentials");
string jwtToken = GenerateToken(getEmail);
return Ok(jwtToken);
}
return NotFound("Email not found");
}
private string GenerateToken(string getEmail)
{
var key = Encoding.UTF8.GetBytes(config["Authentication:Key"]!);
var securityKey = new SymmetricSecurityKey(key);
var credential = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var claims = new[] { new Claim(ClaimTypes.Email, getEmail!) };
var token = new JwtSecurityToken(
issuer: config["Authentication:Issuer"],
audience: config["authentication:Audience"],
claims:claims,
expires: null,
signingCredentials: credential);
return new JwtSecurityTokenHandler().WriteToken(token);
}
[HttpPost("register/{email}/{password}")]
public async Task<IActionResult> Register(string email, string password)
{
await Task.Delay(500);
var getEmail = UserData!.Keys.Where(e => e.Equals(email)).FirstOrDefault();
if (!string.IsNullOrEmpty(getEmail))
return BadRequest("User already exist");
UserData[email] = password;
return Ok("User create successfully");
}
}
}
namespace Gateway.Middlewares
{
public class TokenCheckerMiddleware(RequestDelegate next)
{
public async Task InvokeAsync(HttpContext context)
{
string requestPath = context.Request.Path.Value!;
if (requestPath.Contains("account/login", StringComparison.InvariantCultureIgnoreCase)
|| requestPath.Contains("account/register", StringComparison.InvariantCultureIgnoreCase)
|| requestPath.Equals("/"))
{
await next(context);
}
else
{
var authHeader = context.Request.Headers.Authorization;
if (authHeader.FirstOrDefault() == null)
{
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
await context.Response.WriteAsync("Sorry, Access denied");
}
else
{
await next(context);
}
}
}
}
}
{
"Routes": [
{
"DownstreamPathTemplate": "/api/user",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 7001
}
],
"UpstreamPathTemplate": "/api/user",
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ]
},
{
"DownstreamPathTemplate": "/api/weatherforecast",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 7002
}
],
"UpstreamPathTemplate": "/api/weatherforecast",
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ]
},
{
"DownstreamPathTemplate": "/api/account/{email}/{password}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 7003
}
],
"UpstreamPathTemplate": "/api/account/{email}/{password}",
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ]
}
],
"GlobalConfiguration": {
"BaseUrl": "https://localhost:7000"
}
Conclusion
Great job! We've successfully added JWT authentication to our microservices architecture using Ocelot as our API gateway. By doing this, we've significantly enhanced the security of our application, ensuring that only authenticated users can access our services.
In our scenario, where sensitive data and transactions are involved, JWT authentication is crucial. It helps us prevent unauthorized access, protects our data, and ensures a secure communication channel between clients and services. This extra layer of security is not just a best practice but a necessity in today's world of microservices and distributed systems.
Remember, implementing security measures like JWT authentication is an ongoing process. Stay tuned for more videos where we'll dive even deeper into securing our applications and exploring advanced techniques.
Comments
Post a Comment