feat: add rest client for modular monolith

This commit is contained in:
Meysam Hadeli 2025-04-07 02:41:14 +03:30
parent ff8badcd4a
commit d5312430ac
36 changed files with 875 additions and 85 deletions

View File

@ -7,6 +7,16 @@
- [Key Features](#key-features)
- [When to Use](#when-to-use)
- [Challenges](#challenges)
- [Modular Monolith Architecture Design](#modular-monolith-architecture-design)
- [Development Setup](#development-setup)
- [Dotnet Tools Packages](#dotnet-tools-packages)
- [Husky](#husky)
- [Upgrade Nuget Packages](#upgrade-nuget-packages)
- [How to Run](#how-to-run)
- [Build](#build)
- [Run](#run)
- [Test](#test)
- [Documentation Apis](#documentation-apis)
## Key Features
@ -27,3 +37,66 @@
- Still a single deployment unit, so scaling is limited.
- Requires careful design to avoid tight coupling between modules.
- Not as scalable or fault-tolerant as microservices.
## Modular Monolith Architecture Design
![](./assets/booking-modular-monolith.png)
## Development Setup
### Dotnet Tools Packages
For installing our requirement packages with .NET cli tools, we need to install `dotnet tool manifest`.
```bash
dotnet new tool-manifest
```
And after that we can restore our dotnet tools packages with .NET cli tools from `.config` folder and `dotnet-tools.json` file.
```
dotnet tool restore
```
### Husky
Here we use `husky` to handel some pre commit rules and we used `conventional commits` rules and `formatting` as pre commit rules, here in [package.json](.././package.json). of course, we can add more rules for pre commit in future. (find more about husky in the [documentation](https://typicode.github.io/husky/get-started.html))
We need to install `husky` package for `manage` `pre commits hooks` and also I add two packages `@commitlint/cli` and `@commitlint/config-conventional` for handling conventional commits rules in [package.json](.././package.json).
Run the command bellow in the root of project to install all npm dependencies related to husky:
```bash
npm install
```
> Note: In the root of project we have `.husky` folder and it has `commit-msg` file for handling conventional commits rules with provide user friendly message and `pre-commit` file that we can run our `scripts` as a `pre-commit` hooks. that here we call `format` script from [package.json](./package.json) for formatting purpose.
### Upgrade Nuget Packages
For upgrading our nuget packages to last version, we use the great package [dotnet-outdated](https://github.com/dotnet-outdated/dotnet-outdated).
Run the command below in the root of project to upgrade all of packages to last version:
```bash
dotnet outdated -u
```
## How to Run
> ### Build
To `build` all modules, run this command in the `root` of the project:
```bash
dotnet build
```
> ### Run
To `run` all modules, run this command in the root of the `Api` folder where the `csproj` file is located:
```bash
dotnet run
```
> ### Test
To `test` all modules, run this command in the `root` of the project:
```bash
dotnet test
```
> ### Documentation Apis
Each microservice provides `API documentation` and navigate to `/swagger` for `Swagger OpenAPI` or `/scalar/v1` for `Scalar OpenAPI` to visit list of endpoints.
As part of API testing, I created the [booking.rest](./booking.rest) file which can be run with the [REST Client](https://github.com/Huachao/vscode-restclient) `VSCode plugin`.

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 541 KiB

View File

@ -0,0 +1,230 @@
@booking-modular-monolith-api=https://localhost:5000
@contentType = application/json
@flightid = "3c5c0000-97c6-fc34-2eb9-08db322230c9"
@passengerId = "8c9c0000-97c6-fc34-2eb9-66db322230c9"
################################# Identity API #################################
###
# @name Authenticate
POST {{booking-modular-monolith-api}}/connect/token
Content-Type: application/x-www-form-urlencoded
grant_type=password
&client_id=client
&client_secret=secret
&username=samh
&password=Admin@123456
&scope=booking-modular-monolith
###
###
# @name Register_New_User
POST {{booking-modular-monolith-api}}/api/v1/identity/register-user
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
{
"firstName": "John",
"lastName": "Do",
"username": "admin",
"passportNumber": "412900000",
"email": "admin@admin.com",
"password": "Admin@12345",
"confirmPassword": "Admin@12345"
}
###
################################# Flight API #################################
###
# @name Create_Seat
Post {{booking-modular-monolith-api}}/api/v1/flight/seat
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
{
"seatNumber": "1255",
"type": 1,
"class": 1,
"flightId": "3c5c0000-97c6-fc34-2eb9-08db322230c9"
}
###
###
# @name Reserve_Seat
Post {{booking-modular-monolith-api}}/api/v1/flight/reserve-seat
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
{
"flightId": "3c5c0000-97c6-fc34-2eb9-08db322230c9",
"seatNumber": "1255"
}
###
###
# @name Get_Available_Seats
GET {{booking-modular-monolith-api}}/api/v1/flight/get-available-seats/{{flightid}}
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
###
###
# @name Get_Flight_By_Id
GET {{booking-modular-monolith-api}}/api/v1/flight/{{flightid}}
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
###
###
# @name Get_Available_Flights
GET {{booking-modular-monolith-api}}/api/v1/flight/get-available-flights
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
###
###
# @name Create_Flights
POST {{booking-modular-monolith-api}}/api/v1/flight
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
{
"flightNumber": "12BB",
"aircraftId": "3c5c0000-97c6-fc34-fcd3-08db322230c8",
"departureAirportId": "3c5c0000-97c6-fc34-a0cb-08db322230c8",
"departureDate": "2022-03-01T14:55:41.255Z",
"arriveDate": "2022-03-01T14:55:41.255Z",
"arriveAirportId": "3c5c0000-97c6-fc34-fc3c-08db322230c8",
"durationMinutes": 120,
"flightDate": "2022-03-01T14:55:41.255Z",
"status": 1,
"price": 8000
}
###
###
# @name Update_Flights
PUT {{booking-modular-monolith-api}}/api/v1/flight
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
{
"id": 1,
"flightNumber": "BD467",
"aircraftId": "3c5c0000-97c6-fc34-fcd3-08db322230c8",
"departureAirportId": "3c5c0000-97c6-fc34-a0cb-08db322230c8",
"departureDate": "2022-04-23T12:17:45.140Z",
"arriveDate": "2022-04-23T12:17:45.140Z",
"arriveAirportId": "3c5c0000-97c6-fc34-fc3c-08db322230c8",
"durationMinutes": 120,
"flightDate": "2022-04-23T12:17:45.140Z",
"status": 4,
"isDeleted": false,
"price": 99000
}
###
###
# @name Delete_Flights
DELETE {{booking-modular-monolith-api}}/api/v1/flight/{{flightid}}
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
###
###
# @name Create_Airport
POST {{booking-modular-monolith-api}}/api/v1/flight/airport
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
{
"name": "mehrabad",
"address": "tehran",
"code": "12YD"
}
###
###
# @name Create_Aircraft
POST {{booking-modular-monolith-api}}/api/v1/flight/aircraft
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
{
"name": "airbus2",
"model": "322",
"manufacturingYear": 2012
}
###
################################# Passenger API #################################
###
# @name Complete_Registration_Passenger
POST {{booking-modular-monolith-api}}/api/v1/passenger/complete-registration
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
{
"passportNumber": "412900000000",
"passengerType": 1,
"age": 30
}
###
###
# @name Get_Passenger_By_Id
GET {{booking-modular-monolith-api}}/api/v1/passenger/{{passengerId}}
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
###
################################# Booking API #################################
###
# @name Create_Booking
POST {{booking-modular-monolith-api}}/api/v1/booking
accept: application/json
Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
{
"passengerId": "8c9c0000-97c6-fc34-2eb9-66db322230c9",
"flightId": "3c5c0000-97c6-fc34-2eb9-08db322230c9",
"description": "I want to fly to iran"
}
###

View File

@ -4,7 +4,6 @@ using BuildingBlocks.Exception;
using BuildingBlocks.HealthCheck;
using BuildingBlocks.Jwt;
using BuildingBlocks.Logging;
using BuildingBlocks.Mapster;
using BuildingBlocks.MassTransit;
using BuildingBlocks.OpenApi;
using BuildingBlocks.OpenTelemetryCollector;
@ -12,7 +11,6 @@ using BuildingBlocks.PersistMessageProcessor;
using BuildingBlocks.ProblemDetails;
using BuildingBlocks.Web;
using Figgle;
using FluentValidation;
using Microsoft.AspNetCore.Mvc;
using Serilog;
@ -38,8 +36,8 @@ public static class SharedInfrastructureExtensions
Console.WriteLine(FiggleFonts.Standard.Render(appOptions.Name));
builder.AddCustomSerilog(builder.Environment);
builder.Services.AddScoped<ICurrentUserProvider, CurrentUserProvider>();
builder.Services.AddJwt();
builder.Services.AddScoped<ICurrentUserProvider, CurrentUserProvider>();
builder.Services.AddTransient<AuthHeaderHandler>();
builder.Services.AddPersistMessageProcessor();
@ -85,9 +83,6 @@ public static class SharedInfrastructureExtensions
});
builder.Services.AddEasyCaching(options => { options.UseInMemory(builder.Configuration, "mem"); });
builder.Services.AddValidatorsFromAssemblies(AppDomain.CurrentDomain.GetAssemblies());
builder.Services.AddCustomMapster(AppDomain.CurrentDomain.GetAssemblies());
builder.Services.AddProblemDetails();
return builder;

View File

@ -7,8 +7,6 @@ using Passenger.Extensions.Infrastructure;
var builder = WebApplication.CreateBuilder(args);
builder.AddMinimalEndpoints(assemblies: AppDomain.CurrentDomain.GetAssemblies());
builder.AddSharedInfrastructure();
builder.AddFlightModules();
@ -16,20 +14,19 @@ builder.AddIdentityModules();
builder.AddPassengerModules();
builder.AddBookingModules();
var app = builder.Build();
// ref: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-7.0#routing-basics
app.UseAuthentication();
app.UseAuthorization();
app.MapMinimalEndpoints();
app.UserSharedInfrastructure();
app.UseFlightModules();
app.UseIdentityModules();
app.UsePassengerModules();
app.UseBookingModules();
app.UserSharedInfrastructure();
app.MapMinimalEndpoints();
app.Run();

View File

@ -26,10 +26,9 @@
"ConnectionString": "esdb://localhost:2113?tls=false"
},
"Jwt": {
"Authority": "http://localhost:5001",
"Audience": "booking_modular_monolith",
"RequireHttpsMetadata": false,
"MetadataAddress": "http://localhost:5001/.well-known/openid-configuration"
"Authority": "https://localhost:5000",
"Audience": "booking-modular-monolith",
"RequireHttpsMetadata": false
},
"PersistMessageOptions": {
"Interval": 30,

View File

@ -0,0 +1 @@
{"Version":1,"Id":"296345BF73910ADD1DAC302B848E47E7","Created":"2025-04-06T20:57:25.1670058Z","Algorithm":"RS256","IsX509Certificate":false,"Data":"CfDJ8KNpFTgHKl5Nl-o13RQ8rseNpYdUTB-_FLsIGbeu6jM5x9l_rDfygUsYH6TAnyqXDFeW4U7xf8kJXDDvH1V0jkKcQaHFWYcZnKAirRBnuReu2OcaGWcn0vDccI5liTTRfp_Dknwhf3jgrU-LOBlPDoVGWwTwOQHXa4iHQjfOCG77Ey6CmJZ0w6JMi802tSMbpc2G2376b05GuzpoKwfgG_F8ZJcAtl1cql4KD11CcynPTNqK0fXOcIeGCQKgJDkJp_cHlk-sv4xJTFl5nqRx62v9auoB3AeKxqRqKqserGT-ZFYDeSxOlgmDSreVFezZ4tYd80Iq-ZpQXK5e3uz8gJ1B37_ySzgF_Rkscf67FivIqcpcV-WZzvnKXeQP0Wo7B7Qt8sKwCAW-vh3X5iMdDi-tecOWaRqeNrffbjd4efP1FK5wqmNrZirrcuCZDgPyYUiB1bSUE1HSj5vW4kFy_NF-3k0EVcQf5KqJpJ9QkTQgmTPkFCwwEcyX-P2hA21G64_M_7EjZXnjw29xjnkI7zO3mx3sA5bwPf6sCmxgE6joaI6P7G4u8JB5pbSHynOWWNTWRZm8YHngZCfK1DZa6Y-uAnrNzVQdcbB-uVGwszavP3Ohqtu7NBCaIkIhyT9N783n5-J8KAbSKu2FBF-qwNaUcmSAhbnRLyQwou-F0sxgM9iLwNcCo6jcgqz5g3MBEIcWa5IKdbtYXQQzbj3NlKmYg1l-x0SrxZD9403gNIS-zCEWLPEgpLr-NU06_Y5Vkbvn8jHKAr45nDFvY_osVvCPQ8qFuq_P-z3HMqFrfuPNlLrf_ZoJCpIKYNdXPJwHQXzGpz41QiN2omk52K5N8UCiGnDog66tJZAqGjtWWHpFCF2O4LXA9uEwnlD06N_i1T9umOtLnlGsF5SM0G3YjG_G8APqd6GDnJsM1wBoVXzzldGvS8GEwwxvVRGvLrSljPdR_l-8JifzUzhIOxMdlZUE8D9tQJhqZJovm34kfgx8AA0j4FQxAKPUhz99dapc5rmP1pgkuv7b9ZgtWa9js16GUJUYV3Dd6HC3lWU4zdXnQIsJPBUdgsiKptAXayc1KevAzw7o2PB7_auENui4cj1MuDxbaf9yrq9ZIol_tPw5rdN440vhHPIPzVi-1Wv0YyvyPD0fj2GAU5fL97lVlCprWuM71-rjVtARrn0pbf4ENBYk4ABWWke8ZHppbdFQQbjBv-yKCeiGA7qbRAeb_NMK2wmWUGz9DTVWtb04kmitXvg1-aj6ZwY-uIDSY5uaHPz7b8mxFywlSQ9plQzIkb-EfZk6RWxW1-NqyHMEAryM4QxwdDX9LjSo37CPdHCdOSRsMzH6zGH0_SgeN4W25Lk0RhoBHMMQk_gF5FCXjDteFlAdPFw9K5qmVVohHfEnAMDUZ4xYYgDx0Z254jsbSIFOuqEmUvmb5WvbKFtlcLrpFAuoqcNLfI61JM0LLxZNjpktGOMX5q1E_tYm5Y-bxd6W_2r-UUkCTKWJMp7_wr2CJPyegVshEBuUaO4_GyndCTY9_jh4OEYgyFQliEg66g3CUVy7ZBERrfz1CiHmpTqoKbs3toPsHMrB6yaQe9UtcYzLBRP3OVku3WmE1IylfUsZ64YA2DBU399JjYckXlWU3PxH9GAxcnIW8cU_29XZZ0ueGLFeSRP0mBb8TqVIcqd3xoAUbZGPnleme-D44yco8ZSGFVhQqt5qstzIA2DQALjVf2E5vg-yL8Gj9s5q-xjPjBgZgyW23gbBEO6PynDK3jfnucHXcLsHMpvZwyV1yaU3314mNLUpu241_7ukMuWC5FmxaVWqe4n9h-W479YlK5WmI5TDmWcc12DQI92eIAYCSYA60SOJhnuGsyFHwedfxIjVjouZeAWWHj1QOM3uZ1rwYOB0DZSlqI6C2kecv4D2CFq7gYosBxQX9fSnJ2MyUiGOxbdlRtwGB_dtRtlqWpt-acu-l9i5jNwdM6QnNejoPthvWPCcvfaaqFjWjnZQQKSBBfWV9Coe7mnaJYhyqWFUQ4AKcDuboQ3k3jj2p-5LTnbFlTQ3SzLfsgjLjpD5hqIY1ND5NWOT3D0pQumfh5tJxgSa0g-HhW7XBSGs2783OFdgAMuxCkZUgisdu0MRyQzdqWEY30trlpnpsAGOO3E8MMxQ2COy7Y-WrUykioag1qkJTbT-1FgHgw9Qj4dnQ136_tC3BvVrmO6pId26PzdPDpV_4T5vNLoyuiyyUqnHcKOETFrHpbj2cXmi-sYuqrwfNZKfcPIsAkekmcWlLd9s4glvD3xJ0SB0s6gJURjvupdD96l2kfdHw8qieB0ovlGISrpjnAKGn6F81_32rYULB-NDN8H4aTdiVmhvwf6KkpXHA9Euuyyir4BqHmIknr8WWuugIMxRw3ysCS4OIV5ocsjzIfQ9r_15bNWsoyWPDkVnKcS1ffbURzYPNIqTO6Ik5iC7rk705WAxaojy","DataProtected":true}

View File

@ -50,7 +50,7 @@ public class CreateBookingEndpoint : IMinimalEndpoint
return Results.Ok(response);
})
.RequireAuthorization(nameof(ApiScope))
.RequireAuthorization()
.WithName("CreateBooking")
.WithApiVersionSet(builder.NewApiVersionSet("Booking").Build())
.Produces<CreateBookingResponseDto>()

View File

@ -1,7 +1,10 @@
using Booking.Data;
using BuildingBlocks.Core;
using BuildingBlocks.EventStoreDB;
using BuildingBlocks.Mapster;
using BuildingBlocks.Mongo;
using BuildingBlocks.Web;
using FluentValidation;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
@ -12,6 +15,9 @@ public static class InfrastructureExtensions
public static WebApplicationBuilder AddBookingModules(this WebApplicationBuilder builder)
{
builder.Services.AddScoped<IEventMapper, EventMapper>();
builder.AddMinimalEndpoints(assemblies: typeof(BookingRoot).Assembly);
builder.Services.AddValidatorsFromAssembly(typeof(BookingRoot).Assembly);
builder.Services.AddCustomMapster(typeof(BookingRoot).Assembly);
builder.AddMongoDbContext<BookingReadDbContext>();
// ref: https://github.com/oskardudycz/EventSourcing.NetCore/tree/main/Sample/EventStoreDB/ECommerce

View File

@ -54,7 +54,7 @@ public class CreateAircraftEndpoint : IMinimalEndpoint
return Results.Ok(response);
})
.RequireAuthorization(nameof(ApiScope))
.RequireAuthorization()
.WithName("CreateAircraft")
.WithApiVersionSet(builder.NewApiVersionSet("Flight").Build())
.Produces<CreateAircraftResponseDto>()

View File

@ -51,7 +51,7 @@ public class CreateAirportEndpoint : IMinimalEndpoint
return Results.Ok(response);
})
.RequireAuthorization(nameof(ApiScope))
.RequireAuthorization()
.WithName("CreateAirport")
.WithApiVersionSet(builder.NewApiVersionSet("Flight").Build())
.Produces<CreateAirportResponseDto>()

View File

@ -1,9 +1,12 @@
using BuildingBlocks.Core;
using BuildingBlocks.EFCore;
using BuildingBlocks.Mapster;
using BuildingBlocks.Mongo;
using BuildingBlocks.Web;
using Flight.Data;
using Flight.Data.Seed;
using Flight.GrpcServer.Services;
using FluentValidation;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
@ -15,6 +18,9 @@ public static class InfrastructureExtensions
public static WebApplicationBuilder AddFlightModules(this WebApplicationBuilder builder)
{
builder.Services.AddScoped<IEventMapper, EventMapper>();
builder.AddMinimalEndpoints(assemblies: typeof(FlightRoot).Assembly);
builder.Services.AddValidatorsFromAssembly(typeof(FlightRoot).Assembly);
builder.Services.AddCustomMapster(typeof(FlightRoot).Assembly);
builder.AddCustomDbContext<FlightDbContext>(nameof(Flight));
builder.Services.AddScoped<IDataSeeder, FlightDataSeeder>();
builder.AddMongoDbContext<FlightReadDbContext>();

View File

@ -14,7 +14,7 @@ public static class MediatRExtensions
services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblies(typeof(FlightRoot).Assembly));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
// services.AddScoped(typeof(IPipelineBehavior<,>), typeof(EfTxFlightBehavior<,>));
services.AddScoped(typeof(IPipelineBehavior<,>), typeof(EfTxFlightBehavior<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(CachingBehavior<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(InvalidateCachingBehavior<,>));

View File

@ -59,7 +59,7 @@ public class CreateFlightEndpoint : IMinimalEndpoint
return Results.CreatedAtRoute("GetFlightById", new { id = result.Id }, response);
})
.RequireAuthorization(nameof(ApiScope))
.RequireAuthorization()
.WithName("CreateFlight")
.WithApiVersionSet(builder.NewApiVersionSet("Flight").Build())
.Produces<CreateFlightResponseDto>(StatusCodes.Status201Created)

View File

@ -45,7 +45,7 @@ public class DeleteFlightEndpoint : IMinimalEndpoint
return Results.NoContent();
})
.RequireAuthorization(nameof(ApiScope))
.RequireAuthorization()
.WithName("DeleteFlight")
.WithApiVersionSet(builder.NewApiVersionSet("Flight").Build())
.Produces(StatusCodes.Status204NoContent)

View File

@ -46,7 +46,7 @@ public class GetAvailableFlightsEndpoint : IMinimalEndpoint
return Results.Ok(response);
})
.RequireAuthorization(nameof(ApiScope))
.RequireAuthorization()
.WithName("GetAvailableFlights")
.WithApiVersionSet(builder.NewApiVersionSet("Flight").Build())
.Produces<GetAvailableFlightsResponseDto>()

View File

@ -39,7 +39,7 @@ public class GetFlightByIdEndpoint : IMinimalEndpoint
return Results.Ok(response);
})
.RequireAuthorization(nameof(ApiScope))
.RequireAuthorization()
.WithName("GetFlightById")
.WithApiVersionSet(builder.NewApiVersionSet("Flight").Build())
.Produces<GetFlightByIdResponseDto>()

View File

@ -56,7 +56,7 @@ public class UpdateFlightEndpoint : IMinimalEndpoint
return Results.NoContent();
})
.RequireAuthorization(nameof(ApiScope))
.RequireAuthorization()
.WithName("UpdateFlight")
.WithApiVersionSet(builder.NewApiVersionSet("Flight").Build())
.Produces(StatusCodes.Status204NoContent)

View File

@ -44,7 +44,7 @@ public class CreateSeatEndpoint : IMinimalEndpoint
public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder builder)
{
builder.MapPost($"{EndpointConfig.BaseApiPath}/flight/seat", CreateSeat)
.RequireAuthorization(nameof(ApiScope))
.RequireAuthorization()
.WithName("CreateSeat")
.WithApiVersionSet(builder.NewApiVersionSet("Flight").Build())
.Produces<CreateSeatResponseDto>()

View File

@ -34,7 +34,7 @@ public class GetAvailableSeatsEndpoint : IMinimalEndpoint
public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder builder)
{
builder.MapGet($"{EndpointConfig.BaseApiPath}/flight/get-available-seats/{{id}}", GetAvailableSeats)
.RequireAuthorization(nameof(ApiScope))
.RequireAuthorization()
.WithName("GetAvailableSeats")
.WithApiVersionSet(builder.NewApiVersionSet("Flight").Build())
.Produces<GetAvailableSeatsResponseDto>()

View File

@ -35,7 +35,7 @@ public class ReserveSeatEndpoint : IMinimalEndpoint
public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder builder)
{
builder.MapPost($"{EndpointConfig.BaseApiPath}/flight/reserve-seat", ReserveSeat)
.RequireAuthorization(nameof(ApiScope))
.RequireAuthorization()
.WithName("ReserveSeat")
.WithApiVersionSet(builder.NewApiVersionSet("Flight").Build())
.Produces<ReserveSeatResponseDto>()

View File

@ -25,7 +25,8 @@ public static class Config
new(Constants.StandardScopes.FlightApi),
new(Constants.StandardScopes.PassengerApi),
new(Constants.StandardScopes.BookingApi),
new(Constants.StandardScopes.IdentityApi)
new(Constants.StandardScopes.IdentityApi),
new(Constants.StandardScopes.BookingModularMonolith),
};
@ -35,7 +36,8 @@ public static class Config
new(Constants.StandardScopes.FlightApi),
new(Constants.StandardScopes.PassengerApi),
new(Constants.StandardScopes.BookingApi),
new(Constants.StandardScopes.IdentityApi)
new(Constants.StandardScopes.IdentityApi),
new(Constants.StandardScopes.BookingModularMonolith),
};
public static IEnumerable<Client> Clients =>
@ -56,7 +58,8 @@ public static class Config
Constants.StandardScopes.FlightApi,
Constants.StandardScopes.PassengerApi,
Constants.StandardScopes.BookingApi,
Constants.StandardScopes.IdentityApi
Constants.StandardScopes.IdentityApi,
Constants.StandardScopes.BookingModularMonolith,
},
AccessTokenLifetime = 3600, // authorize the client to access protected resources
IdentityTokenLifetime = 3600 // authenticate the user

View File

@ -1,5 +1,8 @@
using BuildingBlocks.Core;
using BuildingBlocks.EFCore;
using BuildingBlocks.Mapster;
using BuildingBlocks.Web;
using FluentValidation;
using Identity.Configurations;
using Identity.Data;
using Identity.Data.Seed;
@ -15,6 +18,9 @@ public static class InfrastructureExtensions
public static WebApplicationBuilder AddIdentityModules(this WebApplicationBuilder builder)
{
builder.Services.AddScoped<IEventMapper, EventMapper>();
builder.AddMinimalEndpoints(assemblies: typeof(IdentityRoot).Assembly);
builder.Services.AddValidatorsFromAssembly(typeof(IdentityRoot).Assembly);
builder.Services.AddCustomMapster(typeof(IdentityRoot).Assembly);
builder.AddCustomDbContext<IdentityContext>(nameof(Identity));
builder.Services.AddScoped<IDataSeeder, IdentityDataSeeder>();
builder.AddCustomIdentityServer();

View File

@ -16,7 +16,7 @@ public static class MediatRExtensions
services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblies(typeof(IdentityRoot).Assembly));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
// services.AddScoped(typeof(IPipelineBehavior<,>), typeof(EfTxIdentityBehavior<,>));
services.AddScoped(typeof(IPipelineBehavior<,>), typeof(EfTxIdentityBehavior<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(CachingBehavior<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(InvalidateCachingBehavior<,>));

View File

@ -15,5 +15,6 @@ public static class Constants
public const string PassengerApi = "passenger-api";
public const string BookingApi = "booking-api";
public const string IdentityApi = "identity-api";
public const string BookingModularMonolith = "booking-modular-monolith";
}
}

View File

@ -9,7 +9,6 @@ using BuildingBlocks.Contracts.EventBus.Messages;
using BuildingBlocks.Core;
using BuildingBlocks.Core.CQRS;
using BuildingBlocks.Web;
using Duende.IdentityServer.EntityFramework.Entities;
using Exceptions;
using FluentValidation;
using Mapster;
@ -48,7 +47,7 @@ public class RegisterNewUserEndpoint : IMinimalEndpoint
return Results.Ok(response);
})
// .RequireAuthorization()
.RequireAuthorization()
.WithName("RegisterUser")
.WithApiVersionSet(builder.NewApiVersionSet("Identity").Build())
.Produces<RegisterNewUserResponseDto>()

View File

@ -1,6 +1,9 @@
using BuildingBlocks.Core;
using BuildingBlocks.EFCore;
using BuildingBlocks.Mapster;
using BuildingBlocks.Mongo;
using BuildingBlocks.Web;
using FluentValidation;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Passenger.Data;
@ -13,6 +16,9 @@ public static class InfrastructureExtensions
public static WebApplicationBuilder AddPassengerModules(this WebApplicationBuilder builder)
{
builder.Services.AddScoped<IEventMapper, EventMapper>();
builder.AddMinimalEndpoints(assemblies: typeof(PassengerRoot).Assembly);
builder.Services.AddValidatorsFromAssembly(typeof(PassengerRoot).Assembly);
builder.Services.AddCustomMapster(typeof(PassengerRoot).Assembly);
builder.AddCustomDbContext<PassengerDbContext>(nameof(Passenger));
builder.AddMongoDbContext<PassengerReadDbContext>();

View File

@ -14,7 +14,7 @@ public static class MediatRExtensions
services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblies(typeof(PassengerRoot).Assembly));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
// services.AddScoped(typeof(IPipelineBehavior<,>), typeof(EfTxPassengerBehavior<,>));
services.AddScoped(typeof(IPipelineBehavior<,>), typeof(EfTxPassengerBehavior<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(CachingBehavior<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(InvalidateCachingBehavior<,>));

View File

@ -51,7 +51,7 @@ public class CompleteRegisterPassengerEndpoint : IMinimalEndpoint
return Results.Ok(response);
})
.RequireAuthorization(nameof(ApiScope))
.RequireAuthorization()
.WithName("CompleteRegisterPassenger")
.WithApiVersionSet(builder.NewApiVersionSet("Passenger").Build())
.Produces<CompleteRegisterPassengerResponseDto>()

View File

@ -36,7 +36,7 @@ public class GetPassengerByIdEndpoint : IMinimalEndpoint
return Results.Ok(response);
})
.RequireAuthorization(nameof(ApiScope))
.RequireAuthorization()
.WithName("GetPassengerById")
.WithApiVersionSet(builder.NewApiVersionSet("Passenger").Build())
.Produces<GetPassengerByIdResponseDto>()

View File

@ -1,6 +1,6 @@
<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36" version="26.0.11">
<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36" version="26.1.2">
<diagram name="Page-1" id="LwSOovy8OdwzHFtQ82wI">
<mxGraphModel dx="3968" dy="3244" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1100" pageHeight="850" math="0" shadow="0">
<mxGraphModel dx="3490" dy="2987" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1100" pageHeight="850" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
@ -10,9 +10,6 @@
<mxCell id="PG-S5D8SCmHSsYNVxMVk-73" value="&lt;span style=&quot;color: rgba(0, 0, 0, 0); font-family: monospace; font-size: 0px; text-align: start; text-wrap-mode: nowrap;&quot;&gt;%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22%26lt%3Bb%26gt%3B%26lt%3Bfont%26gt%3BOutbox%20Processor%26lt%3B%2Ffont%26gt%3B%26lt%3B%2Fb%26gt%3B%22%20style%3D%22text%3BstrokeColor%3Dnone%3BfillColor%3Dnone%3Bhtml%3D1%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3BwhiteSpace%3Dwrap%3Brounded%3D0%3BfontSize%3D18%3BfontFamily%3DComic%20Sans%20MS%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%2298%22%20y%3D%22-84%22%20width%3D%22145%22%20height%3D%2230%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E&lt;/span&gt;" style="rounded=1;whiteSpace=wrap;html=1;glass=0;shadow=0;fillColor=#ffe6cc;strokeColor=#d79b00;opacity=50;" parent="1" vertex="1">
<mxGeometry x="80" y="-388" width="310" height="544" as="geometry" />
</mxCell>
<mxCell id="PG-S5D8SCmHSsYNVxMVk-60" value="" style="rounded=1;whiteSpace=wrap;html=1;fontFamily=Helvetica;fontSize=12;fontColor=#333333;labelBackgroundColor=default;fillColor=#f5f5f5;strokeColor=#666666;opacity=80;" parent="1" vertex="1">
<mxGeometry x="70" y="-820" width="1680" height="320" as="geometry" />
</mxCell>
<mxCell id="PG-S5D8SCmHSsYNVxMVk-6" value="" style="rounded=1;whiteSpace=wrap;html=1;glass=0;shadow=0;fillColor=#1ba1e2;strokeColor=#006EAF;fontColor=#ffffff;opacity=10;" parent="1" vertex="1">
<mxGeometry x="120" y="-760" width="370" height="220" as="geometry" />
</mxCell>
@ -110,7 +107,7 @@
<mxCell id="PG-S5D8SCmHSsYNVxMVk-48" style="edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;dashed=1;dashPattern=8 8;strokeColor=default;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=open;endFill=0;endSize=8;flowAnimation=0;" parent="1" source="PG-S5D8SCmHSsYNVxMVk-34" target="PG-S5D8SCmHSsYNVxMVk-29" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="npFnTr0Nz-ztX7RqOmGq-12" style="edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#D44E4E;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;startSize=8;endArrow=open;endFill=0;endSize=8;entryX=0.253;entryY=0.114;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" edge="1" target="PG-S5D8SCmHSsYNVxMVk-72">
<mxCell id="npFnTr0Nz-ztX7RqOmGq-12" style="edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#D44E4E;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;startSize=8;endArrow=open;endFill=0;endSize=8;entryX=0.253;entryY=0.114;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" target="PG-S5D8SCmHSsYNVxMVk-72" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="623" y="-643" as="sourcePoint" />
<mxPoint x="820" y="-200" as="targetPoint" />
@ -211,24 +208,6 @@
<mxPoint x="1527.3099999999995" y="-759.0799999999999" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="PG-S5D8SCmHSsYNVxMVk-62" value="" style="image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=12;image=img/lib/mscae/ResourceGroup.svg;fontFamily=Helvetica;fontColor=default;labelBackgroundColor=default;" parent="1" vertex="1">
<mxGeometry x="129.5" y="-749" width="36.25" height="29" as="geometry" />
</mxCell>
<mxCell id="PG-S5D8SCmHSsYNVxMVk-63" value="" style="image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=12;image=img/lib/mscae/ResourceGroup.svg;fontFamily=Helvetica;fontColor=default;labelBackgroundColor=default;" parent="1" vertex="1">
<mxGeometry x="1330" y="-749" width="36.25" height="29" as="geometry" />
</mxCell>
<mxCell id="PG-S5D8SCmHSsYNVxMVk-64" value="" style="image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=12;image=img/lib/mscae/ResourceGroup.svg;fontFamily=Helvetica;fontColor=default;labelBackgroundColor=default;" parent="1" vertex="1">
<mxGeometry x="930" y="-748" width="36.25" height="29" as="geometry" />
</mxCell>
<mxCell id="PG-S5D8SCmHSsYNVxMVk-65" value="" style="image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=12;image=img/lib/mscae/ResourceGroup.svg;fontFamily=Helvetica;fontColor=default;labelBackgroundColor=default;" parent="1" vertex="1">
<mxGeometry x="532" y="-748" width="36.25" height="29" as="geometry" />
</mxCell>
<mxCell id="PG-S5D8SCmHSsYNVxMVk-68" value="&lt;b&gt;MICROSERVICES&lt;/b&gt;" style="text;strokeColor=none;fillColor=none;html=1;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=15;fontFamily=Comic Sans MS;" parent="1" vertex="1">
<mxGeometry x="143" y="-798" width="130" height="20" as="geometry" />
</mxCell>
<mxCell id="PG-S5D8SCmHSsYNVxMVk-70" value="" style="image;aspect=fixed;html=1;points=[];align=center;fontSize=12;image=img/lib/azure2/ai_machine_learning/Cognitive_Services.svg;fontFamily=Helvetica;fontColor=default;labelBackgroundColor=default;" parent="1" vertex="1">
<mxGeometry x="90" y="-807" width="48.17" height="34" as="geometry" />
</mxCell>
<mxCell id="PG-S5D8SCmHSsYNVxMVk-72" value="" style="shape=image;imageAspect=0;aspect=fixed;verticalLabelPosition=bottom;verticalAlign=top;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaW5ZTWluIG1lZXQiIHZpZXdCb3g9IjAgLTE4IDI1NiAyNTYiIGhlaWdodD0iODAwcHgiIHdpZHRoPSI4MDBweCI+PHBhdGggZmlsbD0iIzkxMjYyNiIgZD0iTTI0NS45NyAxNjguOTQzYy0xMy42NjIgNy4xMjEtODQuNDM0IDM2LjIyLTk5LjUwMSA0NC4wNzUtMTUuMDY3IDcuODU2LTIzLjQzNyA3Ljc4LTM1LjM0IDIuMDktMTEuOTAyLTUuNjktODcuMjE2LTM2LjExMi0xMDAuNzgzLTQyLjU5N0MzLjU2NiAxNjkuMjcxIDAgMTY2LjUzNSAwIDE2My45NTF2LTI1Ljg3NnM5OC4wNS0yMS4zNDUgMTEzLjg3OS0yNy4wMjRjMTUuODI4LTUuNjc5IDIxLjMyLTUuODg0IDM0Ljc5LS45NSAxMy40NzIgNC45MzYgOTQuMDE4IDE5LjQ2OCAxMDcuMzMxIDI0LjM0NGwtLjAwNiAyNS41MWMuMDAyIDIuNTU4LTMuMDcgNS4zNjQtMTAuMDI0IDguOTg4Ii8+PHBhdGggZmlsbD0iI0M2MzAyQiIgZD0iTTI0NS45NjUgMTQzLjIyYy0xMy42NjEgNy4xMTgtODQuNDMxIDM2LjIxOC05OS40OTggNDQuMDcyLTE1LjA2NiA3Ljg1Ny0yMy40MzYgNy43OC0zNS4zMzggMi4wOS0xMS45MDMtNS42ODYtODcuMjE0LTM2LjExMy0xMDAuNzgtNDIuNTk0LTEzLjU2Ni02LjQ4NS0xMy44NS0xMC45NDgtLjUyNC0xNi4xNjYgMTMuMzI2LTUuMjIgODguMjI0LTM0LjYwNSAxMDQuMDU1LTQwLjI4NCAxNS44MjgtNS42NzcgMjEuMzE5LTUuODg0IDM0Ljc4OS0uOTQ4IDEzLjQ3MSA0LjkzNCA4My44MTkgMzIuOTM1IDk3LjEzIDM3LjgxIDEzLjMxNiA0Ljg4MSAxMy44MjcgOC45LjE2NiAxNi4wMiIvPjxwYXRoIGZpbGw9IiM5MTI2MjYiIGQ9Ik0yNDUuOTcgMTI3LjA3NGMtMTMuNjYyIDcuMTIyLTg0LjQzNCAzNi4yMi05OS41MDEgNDQuMDc4LTE1LjA2NyA3Ljg1My0yMy40MzcgNy43NzctMzUuMzQgMi4wODctMTEuOTAzLTUuNjg3LTg3LjIxNi0zNi4xMTItMTAwLjc4My00Mi41OTdDMy41NjYgMTI3LjQwMiAwIDEyNC42NyAwIDEyMi4wODVWOTYuMjA2czk4LjA1LTIxLjM0NCAxMTMuODc5LTI3LjAyM2MxNS44MjgtNS42NzkgMjEuMzItNS44ODUgMzQuNzktLjk1QzE2Mi4xNDIgNzMuMTY4IDI0Mi42ODggODcuNjk3IDI1NiA5Mi41NzRsLS4wMDYgMjUuNTEzYy4wMDIgMi41NTctMy4wNyA1LjM2My0xMC4wMjQgOC45ODciLz48cGF0aCBmaWxsPSIjQzYzMDJCIiBkPSJNMjQ1Ljk2NSAxMDEuMzUxYy0xMy42NjEgNy4xMi04NC40MzEgMzYuMjE4LTk5LjQ5OCA0NC4wNzUtMTUuMDY2IDcuODU0LTIzLjQzNiA3Ljc3Ny0zNS4zMzggMi4wODctMTEuOTAzLTUuNjg2LTg3LjIxNC0zNi4xMTItMTAwLjc4LTQyLjU5NC0xMy41NjYtNi40ODMtMTMuODUtMTAuOTQ3LS41MjQtMTYuMTY3QzIzLjE1MSA4My41MzUgOTguMDUgNTQuMTQ4IDExMy44OCA0OC40N2MxNS44MjgtNS42NzggMjEuMzE5LTUuODg0IDM0Ljc4OS0uOTQ5IDEzLjQ3MSA0LjkzNCA4My44MTkgMzIuOTMzIDk3LjEzIDM3LjgxIDEzLjMxNiA0Ljg4IDEzLjgyNyA4LjkuMTY2IDE2LjAyIi8+PHBhdGggZmlsbD0iIzkxMjYyNiIgZD0iTTI0NS45NyA4My42NTNjLTEzLjY2MiA3LjEyLTg0LjQzNCAzNi4yMi05OS41MDEgNDQuMDc4LTE1LjA2NyA3Ljg1NC0yMy40MzcgNy43NzctMzUuMzQgMi4wODctMTEuOTAzLTUuNjg3LTg3LjIxNi0zNi4xMTMtMTAwLjc4My00Mi41OTVDMy41NjYgODMuOTggMCA4MS4yNDcgMCA3OC42NjV2LTI1Ljg4czk4LjA1LTIxLjM0MyAxMTMuODc5LTI3LjAyMWMxNS44MjgtNS42OCAyMS4zMi01Ljg4NCAzNC43OS0uOTVDMTYyLjE0MiAyOS43NDkgMjQyLjY4OCA0NC4yNzggMjU2IDQ5LjE1NWwtLjAwNiAyNS41MTJjLjAwMiAyLjU1NS0zLjA3IDUuMzYxLTEwLjAyNCA4Ljk4NiIvPjxwYXRoIGZpbGw9IiNDNjMwMkIiIGQ9Ik0yNDUuOTY1IDU3LjkzYy0xMy42NjEgNy4xMi04NC40MzEgMzYuMjItOTkuNDk4IDQ0LjA3NC0xNS4wNjYgNy44NTQtMjMuNDM2IDcuNzc3LTM1LjMzOCAyLjA5Qzk5LjIyNyA5OC40MDQgMjMuOTE1IDY3Ljk4IDEwLjM1IDYxLjQ5Ny0zLjIxNyA1NS4wMTUtMy41IDUwLjU1IDkuODI1IDQ1LjMzMSAyMy4xNTEgNDAuMTEzIDk4LjA1IDEwLjczIDExMy44OCA1LjA1YzE1LjgyOC01LjY3OSAyMS4zMTktNS44ODMgMzQuNzg5LS45NDggMTMuNDcxIDQuOTM1IDgzLjgxOSAzMi45MzQgOTcuMTMgMzcuODExIDEzLjMxNiA0Ljg3NiAxMy44MjcgOC44OTcuMTY2IDE2LjAxNyIvPjxwYXRoIGZpbGw9IiNGRkYiIGQ9Ik0xNTkuMjgzIDMyLjc1N2wtMjIuMDEgMi4yODUtNC45MjcgMTEuODU2LTcuOTU4LTEzLjIzLTI1LjQxNS0yLjI4NCAxOC45NjQtNi44MzktNS42OS0xMC40OTggMTcuNzU1IDYuOTQ0IDE2LjczOC01LjQ4LTQuNTI0IDEwLjg1NSAxNy4wNjcgNi4zOTFNMTMxLjAzMiA5MC4yNzVMODkuOTU1IDczLjIzOGw1OC44Ni05LjAzNS0xNy43ODMgMjYuMDcyTTc0LjA4MiAzOS4zNDdjMTcuMzc1IDAgMzEuNDYgNS40NiAzMS40NiAxMi4xOTQgMCA2LjczNi0xNC4wODUgMTIuMTk1LTMxLjQ2IDEyLjE5NXMtMzEuNDYtNS40Ni0zMS40Ni0xMi4xOTVjMC02LjczNCAxNC4wODUtMTIuMTk0IDMxLjQ2LTEyLjE5NCIvPjxwYXRoIGZpbGw9IiM2MjFCMUMiIGQ9Ik0xODUuMjk1IDM1Ljk5OGwzNC44MzYgMTMuNzY2LTM0LjgwNiAxMy43NTMtLjAzLTI3LjUyIi8+PHBhdGggZmlsbD0iIzlBMjkyOCIgZD0iTTE0Ni43NTUgNTEuMjQzbDM4LjU0LTE1LjI0NS4wMyAyNy41MTktMy43NzkgMS40NzgtMzQuNzkxLTEzLjc1MiIvPjwvc3ZnPg==;" parent="1" vertex="1">
<mxGeometry x="800" y="-169" width="79" height="79" as="geometry" />
</mxCell>
@ -477,7 +456,7 @@
</Array>
</mxGeometry>
</mxCell>
<mxCell id="7DCv9Lc5Xf6xtuzZQ5PP-6" style="edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;strokeColor=#d79b00;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=none;endFill=0;endSize=8;flowAnimation=0;fillColor=#ffe6cc;startArrow=open;startFill=0;" edge="1" parent="1">
<mxCell id="7DCv9Lc5Xf6xtuzZQ5PP-6" style="edgeStyle=orthogonalEdgeStyle;shape=connector;curved=0;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;shadow=0;strokeColor=#d79b00;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;labelBackgroundColor=default;elbow=vertical;startSize=8;endArrow=none;endFill=0;endSize=8;flowAnimation=0;fillColor=#ffe6cc;startArrow=open;startFill=0;" parent="1" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="390" y="-126.59" as="targetPoint" />
<mxPoint x="610" y="-126.59" as="sourcePoint" />

Binary file not shown.

Before

Width:  |  Height:  |  Size: 558 KiB

After

Width:  |  Height:  |  Size: 541 KiB

View File

@ -45,7 +45,7 @@ authorization: bearer {{Authenticate.response.body.access_token}}
"firstName": "John",
"lastName": "Do",
"username": "admin",
"passportNumber": "412900000000",
"passportNumber": "412900000",
"email": "admin@admin.com",
"password": "Admin@12345",
"confirmPassword": "Admin@12345"

View File

@ -13,33 +13,40 @@ public static class JwtExtensions
{
var jwtOptions = services.GetOptions<JwtBearerOptions>("Jwt");
services.AddAuthentication(o =>
{
o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddCookie(cfg => cfg.SlidingExpiration = true)
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
{
options.Authority = jwtOptions.Authority;
options.TokenValidationParameters = new TokenValidationParameters
services.AddAuthentication(
o =>
{
ValidateAudience = false,
ClockSkew = TimeSpan.FromSeconds(2) // For prevent add default value (5min) to life time token!
};
options.RequireHttpsMetadata = jwtOptions.RequireHttpsMetadata;
options.MetadataAddress = jwtOptions.MetadataAddress;
});
o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddCookie(cfg => cfg.SlidingExpiration = true)
.AddJwtBearer(
JwtBearerDefaults.AuthenticationScheme,
options =>
{
options.Authority = jwtOptions.Authority;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false,
ClockSkew = TimeSpan.FromSeconds(2) // For prevent add default value (5min) to life time token!
};
options.RequireHttpsMetadata = jwtOptions.RequireHttpsMetadata;
options.MetadataAddress = jwtOptions.MetadataAddress;
});
if (!string.IsNullOrEmpty(jwtOptions.Audience))
{
services.AddAuthorization(options =>
options.AddPolicy(nameof(ApiScope), policy =>
{
policy.RequireAuthenticatedUser();
policy.RequireClaim("scope", jwtOptions.Audience);
})
);
services.AddAuthorization(
options =>
options.AddPolicy(
nameof(ApiScope),
policy =>
{
policy.RequireAuthenticatedUser();
policy.RequireClaim("scope", jwtOptions.Audience);
}));
}
return services;