https://github.com/manusoft/api-gateway-sample
One api project can control multiple apis in asp.net web api. dotnet-8
https://github.com/manusoft/api-gateway-sample
cachemanager gateway-api jwt-authentication load-balancer middlewares ocelot-api-gateway rate-limit
Last synced: 4 months ago
JSON representation
One api project can control multiple apis in asp.net web api. dotnet-8
- Host: GitHub
- URL: https://github.com/manusoft/api-gateway-sample
- Owner: manusoft
- License: mit
- Created: 2024-07-17T10:16:03.000Z (12 months ago)
- Default Branch: master
- Last Pushed: 2024-07-24T09:26:09.000Z (11 months ago)
- Last Synced: 2024-12-27T14:44:30.538Z (6 months ago)
- Topics: cachemanager, gateway-api, jwt-authentication, load-balancer, middlewares, ocelot-api-gateway, rate-limit
- Language: C#
- Homepage: https://manusoft.github.io/api-gateway-sample/
- Size: 33.2 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# API-GATEWAY-SAMPLE
One gateway API calls multiple APIs``` http
GET https://localhost:7000/
GET https://localhost:7000/api/user
GET https://localhost:7000/api/weather
GET https://localhost:7000/api/aggregate
POST https://localhost:7000/api/account/{email}/{password}
GET https://localhost:7000/api/account/{email}/{password}
```## 1. Gateway Project
### Ocelot Setup
#### Install nuget package Ocelot and Ocelot.Cache.CacheManager
``` xml
```
#### launchSettings.json
``` json
...
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "",
"applicationUrl": "https://localhost:7000;http://localhost:5275",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
...
```#### ocelot.json
``` json
{
"Routes": [
{
"DownstreamPathTemplate": "/api/user",
"DownstreamScheme": "Http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 7001
},
{
"Host": "localhost",
"Port": 7004
},
{
"Host": "localhost",
"Port": 7005
}
],
"UpstreamPathTemplate": "/api/user",
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ],
"FileCacheOptions": {
"TtlSeconds": 60,
"Region": "default",
"Header": "OC-Caching-Control",
"EnableContentHashing": false
},
"RateLimitOptions": {
"ClientWhitelist": [],
"EnableRateLimiting": true,
"Period": "60s",
"PeriodTimespan": 6,
"Limit": 2
},
"Key": "UserService",
"LoadBalancerOptions": {
"Type": "LeastConnection"
}
},
{
"DownstreamPathTemplate": "/api/weatherforecast",
"DownstreamScheme": "Http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 7002
}
],
"UpstreamPathTemplate": "/api/weatherforecast",
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ],
"FileCacheOptions": {
"TtlSeconds": 60,
"Region": "default",
"Header": "OC-Caching-Control",
"EnableContentHashing": false
},
"RateLimitOptions": {
"ClientWhitelist": [],
"EnableRateLimiting": true,
"Period": "60s",
"PeriodTimespan": 6,
"Limit": 2
},
"Key": "WeatherService"
},
{
"DownstreamPathTemplate": "/api/account/{email}/{password}",
"DownstreamScheme": "Http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 7003
}
],
"UpstreamPathTemplate": "/api/account/{email}/{password}",
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ]
}
],
"Aggregates": [
{
"RouteKeys": [
"UserService",
"WeatherService"
],
"UpstreamPathTemplate": "/api/aggregate"
}
],
"GlobalConfiguration": {
"BaseUrl": "https://localhost:7000"
}
}
```#### Program.cs
``` csharp
using Gateway.Middlewares;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
using Ocelot.Cache.CacheManager;var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddJsonFile("ocelot.json", optional: false, reloadOnChange: true);
builder.Services.AddOcelot().AddCacheManager(options =>
{
options.WithDictionaryHandle();
});
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policyBuilder => policyBuilder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
});var app = builder.Build();
app.UseCors();
app.UseHttpsRedirection();
app.UseMiddleware();
app.UseMiddleware();
app.UseAuthorization();
app.UseOcelot().Wait();
app.Run();```
### Ocelot Cache Manager Configuration
#### ocelot.json
``` json
...
"FileCacheOptions": {
"TtlSeconds": 60,
"Region": "default",
"Header": "OC-Caching-Control",
"EnableContentHashing": false
}
...
```### Ocelot Rate Limit Configuration
#### ocelot.jso
``` json
...
"RateLimitOptions": {
"ClientWhitelist": [],
"EnableRateLimiting": true,
"Period": "60s",
"PeriodTimespan": 6,
"Limit": 2
},
...
```### Ocelot Agregate Configuration
#### ocelot.json
``` json
...
"Key": "UserService"
...
"Key": "WeatherSearvice"
...
"Aggregates": [
{
"RouteKeys": [
"UserService",
"WeatherService"
],
"UpstreamPathTemplate": "/api/aggregate"
}
],
...
```
### Ocelot Load Balance Configuration
#### ocelot.json
``` json
"DownstreamHostAndPorts": [
...
{
"Host": "localhost",
"Port": 7004
},
{
"Host": "localhost",
"Port": 7005
}
],
...
"LoadBalancerOptions": {
"Type": "LeastConnection"
}
...
```### Middelwares
#### InterceptionMiddleware.cs
``` csharp
namespace Gateway.Middlewares;public class InterceptionMiddleware(RequestDelegate next)
{
public async Task InvokeAsync(HttpContext context)
{
context.Request.Headers["Referrer"] = "Api-Gateway";
await next(context);
}
}
```
#### TokenCheckerMiddleware.cs
``` csharp
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);
}}
}
}
```
## 2. Shared Project
### Middleware
#### RestrictAccessMiddleware.cs
``` csharp
using Microsoft.AspNetCore.Http;namespace Shared.Middlewares;
public class RestrictAccessMiddleware(RequestDelegate next)
{
public async Task InvokeAsync(HttpContext context)
{
var referrer = context.Request.Headers["Referrer"].FirstOrDefault();if (string.IsNullOrEmpty(referrer))
{
context.Response.StatusCode = StatusCodes.Status403Forbidden;
await context.Response.WriteAsync("Hmmm, Can't reach this page.");
return;
}
else
{
await next(context);
}
}
}
```
## 3. Identity Project
#### launchSettings.json
``` json
...
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:7001",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7242;http://localhost:7001",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
...
```#### Program.cs
``` csharp
...
app.UseMiddleware();
...
```## 4. Weather Project
#### launchSettings.json
``` json
...
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:7002",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7194;http://localhost:7002",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
...
```#### Program.cs
``` csharp
...
app.UseMiddleware();
...
```## 5. Authetication Project
#### launchSettings.json
``` json
...
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:7003",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7246;http://localhost:7003",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
...
```#### AppSettings.json
``` json
...
"Authentication": {
"Key": "AEkp1N6edDWq7ZBhS9QCtus7+emIxDy0PvoPZxrBmRk=",
"Issuer": "http://localhost:7003",
"Audience": "http://localhost:7003"
}
...
```
#### Program.cs
``` csharp
...
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
var key = Encoding.UTF8.GetBytes(builder.Configuration.GetSection("Authentication:Key").Value!);
string issuer = builder.Configuration.GetSection("Authentication:Issuer").Value!;
string audience = builder.Configuration.GetSection("Authentication:Audience").Value!;options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = issuer,
ValidAudience = audience,
IssuerSigningKey = new SymmetricSecurityKey(key),
};
});builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
{
builder.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin();
});
});
...
app.UseMiddleware();
app.UseCors();
...
```