Browse Source

Added API authentication and implemented middleware validation

pull/1/head
barhen-pfw 1 year ago
parent
commit
54f13b6c5e
  1. 2
      Cloud_Manager/BiskAcdbContext.cs
  2. 32
      Cloud_Manager/Controllers/KeyGeneratorController.cs
  3. 24
      Cloud_Manager/Controllers/SyncControllers/SyncCompanyInfoController.cs
  4. 24
      Cloud_Manager/Controllers/SyncControllers/SyncProductsController.cs
  5. 24
      Cloud_Manager/Controllers/SyncControllers/SyncSalesController.cs
  6. 33
      Cloud_Manager/Controllers/WeatherForecastController.cs
  7. 43
      Cloud_Manager/Middleware/KeyValidationMiddleware.cs
  8. 1
      Cloud_Manager/Models/Enums/AuthEnums.cs
  9. 5
      Cloud_Manager/Models/Interfaces/IKeyService.cs
  10. 135
      Cloud_Manager/Models/ServiceRepo/TokenService.cs
  11. 9
      Cloud_Manager/Program.cs

2
Cloud_Manager/BiskAcdbContext.cs

@ -28,7 +28,7 @@ public partial class BiskAcdbContext : DbContext
if (!optionsBuilder.IsConfigured)
{
string apiKey = m_httpContext.Request.Headers["BISK-API-KEY"]!;
if (AuthEnums.Valid == m_tokenService.ValidateKey(apiKey))
if (!String.IsNullOrEmpty(apiKey) && AuthEnums.Valid == m_tokenService.ValidateKey(apiKey))
{
int? databaseId = m_tokenService.GetDatabaseIdFromKey(apiKey);
string connectionString = m_connection.GetClientConnectionString(databaseId!.Value);

32
Cloud_Manager/Controllers/KeyGeneratorController.cs

@ -0,0 +1,32 @@
using Cloud_Manager.Models.ClientContractModels;
using Cloud_Manager.Models.CustomModels;
using Cloud_Manager.Models.Interfaces;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Cloud_Manager.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class KeyGeneratorController : ControllerBase
{
private readonly IKeyService m_keyService;
public KeyGeneratorController(IKeyService a_keyService)
{
m_keyService = a_keyService;
}
[HttpPost, Route("generate-key")]
public async Task<IActionResult> GenerateKeyAsync(Contract a_contract)
{
if (await m_keyService.GenerateKey(a_contract))
{
return Ok("Key generated");
}
else
{
return BadRequest();
}
}
}
}

24
Cloud_Manager/Controllers/SyncControllers/SyncCompanyInfoController.cs

@ -24,14 +24,14 @@ namespace Cloud_Manager.Controllers.SyncControllers
m_companyInfo = a_companyInfo;
}
// GET: api/<SyncCompanyInfoController>
[Authorize]
[HttpGet, Route("lastsyncdate/{a_tableName}")]
public DateTime GetLastSyncDate(string a_tableName)
{
return m_salesService.GetLastSyncDate(a_tableName);
}
// Post: api/<SyncCompanyInfoController>
[Authorize]
[HttpPost, Route("setsyncdate")]
public void SetLastSyncDate(SyncTimestamp a_timestamp)
{
@ -42,7 +42,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of SystemUserRoles rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/SystemRoles")]
public async Task SyncSyatemRolesAsync(List<Systemuserrole> a_item)
{
@ -53,7 +53,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of TblDriver rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tblDriver")]
public async Task SyncDriversAsync(List<Tbldriver> a_item)
{
@ -64,7 +64,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of CompanyDetails rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tblcompanydetails")]
public async Task SyncCompanyAsync(List<Tblcompanydetail> a_item)
{
@ -75,7 +75,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of TblUsers rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tblusers")]
public async Task SyncUsersAsync(List<Tbluser> a_item)
{
@ -86,7 +86,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of Trucks rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tbltrucks")]
public async Task SyncTrucksAsync(List<Tbltruck> a_item)
{
@ -97,7 +97,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of TblBranch rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tblbranch")]
public async Task SyncBranchAsync(List<Tblbranch> a_item)
{
@ -108,7 +108,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of TblCustomers rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tblcustomers")]
public async Task SyncCustomersAsync(List<Tblcustomer> a_item)
{
@ -119,7 +119,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of TblTruck Inventory rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tbltruckinventory")]
public async Task SyncTruckInventoryAsync(List<Tbltruckinventory> a_item)
{
@ -130,7 +130,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of TblTruckAssignment rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tblTruckAssignment")]
public async Task SyncTruckAssignmentSync(List<Tbltruckassignment> a_item)
{
@ -141,7 +141,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of TblDriverMapping rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tbldrivermappings")]
public async Task SyncTruckDriverMappingSync(List<TbltruckDrivermapping> a_item)
{

24
Cloud_Manager/Controllers/SyncControllers/SyncProductsController.cs

@ -17,14 +17,14 @@ namespace Cloud_Manager.Controllers.SyncControllers
m_productService = a_productService;
}
// GET: api/<SyncProductsController>
[Authorize]
[HttpGet, Route("lastsyncdate/{a_tableName}")]
public DateTime GetLastSyncDate(string a_tableName)
{
return m_productService.GetLastSyncDate(a_tableName);
}
// Post: api/<SyncProductsController>
[Authorize]
[HttpPost, Route("setsyncdate")]
public void SetLastSyncDate(SyncTimestamp a_timestamp)
{
@ -35,7 +35,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of TblProduct rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tblProducts")]
public async Task SyncProductsAsync(List<Tblproduct> a_item)
{
@ -46,7 +46,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of TblInventory rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tblInventory")]
public async Task SyncInventoryAsync(List<Tblinventory> a_item)
{
@ -57,7 +57,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of Restock rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tblRestock")]
public async Task SyncRestockAsync(List<Restocklevel> a_item)
{
@ -68,7 +68,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of TblInventoryEntries rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tblInventoryentry")]
public async Task SyncInventoryEntriesAsync(List<Tblinventoryentry> a_item)
{
@ -79,7 +79,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of PriceChanges rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tlpricechanges")]
public async Task SyncPriceChangesAsync(List<Tblpricechange> a_item)
{
@ -90,7 +90,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of ProductAltUnit rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tblProductAltUnit")]
public async Task SyncProductAltUnitAsync(List<Productaltunit> a_item)
{
@ -101,7 +101,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of TbStock rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tblStock")]
public async Task SyncStockAsync(List<Tbstock> a_item)
{
@ -112,7 +112,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of TblBrands rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tblbrands")]
public async Task SyncBrandsAsync(List<Tblbrand> a_item)
{
@ -123,7 +123,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of TblCategory rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tblCategories")]
public async Task SyncCategoriesAsync(List<Tblcategory> a_item)
{
@ -134,7 +134,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of UnitOfMeasure rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tblunitofmeasure")]
public async Task SyncUnitMeasureAsync(List<Unitofmeasure> a_item)
{

24
Cloud_Manager/Controllers/SyncControllers/SyncSalesController.cs

@ -18,14 +18,14 @@ namespace Cloud_Manager.Controllers.SyncControllers
m_salesService = a_salesService;
}
// GET: api/<SyncSalesController>
[Authorize]
[HttpGet, Route("lastsyncdate/{a_tableName}")]
public DateTime GetLastSyncDate(string a_tableName)
{
return m_salesService.GetLastSyncDate(a_tableName);
}
// Post: api/<SyncSalesController>
[Authorize]
[HttpPost, Route("setsyncdate")]
public void SetLastSyncDate(SyncTimestamp a_timestamp)
{
@ -36,7 +36,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of TblCart rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tblCart")]
public async Task SyncSalesAsync(List<Tblcart> a_item)
{
@ -47,7 +47,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of TblCancelledTransation rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tblcancelledtransaction")]
public async Task SyncCancelledTransactionAsync(List<Tblcancelledtransaction> a_item)
{
@ -58,7 +58,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of TblInvoice rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tblinvoice")]
public async Task SyncInvoiceAsync(List<Tblinvoice> a_item)
{
@ -69,7 +69,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of CreditPurchase rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tblCreditpurchase")]
public async Task SyncCreditPurchaseAsync(List<Creditpurchase> a_item)
{
@ -80,7 +80,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of Customer Account rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tblCustomerAccount")]
public async Task SyncCustomerAccountAsync(List<Customeraccount> a_item)
{
@ -91,7 +91,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of Customer Purchase rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/CustomerPurchase")]
public async Task SyncCustomerPurchaseAsync(List<Tblcustomerpurchase> a_item)
{
@ -102,7 +102,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of Discount logs rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/DiscountLogs")]
public async Task SyncDiscountLogsAsync(List<Tbldiscountlog> a_item)
{
@ -113,7 +113,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of Delivery Head rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tblDeliveryhead")]
public async Task SyncDeliveryHeadAsync(List<Tbldeliveryhead> a_item)
{
@ -124,7 +124,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of Delivery Details rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tblDeliverydetails")]
public async Task SyncDeliveryDetailsAsync(List<Tbldeliverydetail> a_item)
{
@ -135,7 +135,7 @@ namespace Cloud_Manager.Controllers.SyncControllers
/// Endpoint to publish a collection of Delivery Recipient rows to the cloud
/// </summary>
/// <param name="a_item"></param>
[Authorize]
[HttpPost, Route("publish/tblDeliveryrecipient")]
public async Task SyncDeliveryRecipientAsync(List<Tbldeliveryrecipient> a_item)
{

33
Cloud_Manager/Controllers/WeatherForecastController.cs

@ -1,33 +0,0 @@
using Microsoft.AspNetCore.Mvc;
namespace Cloud_Manager.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
}

43
Cloud_Manager/Middleware/KeyValidationMiddleware.cs

@ -0,0 +1,43 @@
using Cloud_Manager.Models.Enums;
using Cloud_Manager.Models.Interfaces;
using Cloud_Manager.Models.ServiceRepo;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
namespace Cloud_Manager.Middleware
{
public class KeyValidationMiddleware
{
private readonly RequestDelegate m_next;
public KeyValidationMiddleware(RequestDelegate next)
{
m_next = next;
}
public async Task InvokeAsync(HttpContext a_httpContext, IKeyService a_keyService)
{
string apiKey = a_httpContext.Request.Headers["BISK-API-KEY"]!;
AuthEnums status = a_keyService.ValidateKey(apiKey);
if (AuthEnums.Valid != status && a_httpContext.Request.Path != "/api/KeyGenerator/generate-key")
{
a_httpContext.Response.StatusCode = StatusCodes.Status401Unauthorized;
await a_httpContext.Response.WriteAsync("API Key status : " + status);
return;
}
await m_next.Invoke(a_httpContext);
}
}
public static class KeyValidationMiddlewareExtensions
{
public static IApplicationBuilder UseKeyValidation(
this IApplicationBuilder builder)
{
return builder.UseMiddleware<KeyValidationMiddleware>();
}
}
}

1
Cloud_Manager/Models/Enums/AuthEnums.cs

@ -9,6 +9,7 @@
Found,
Expired,
Invalid,
Inactive,
Valid,
Successful,
Error

5
Cloud_Manager/Models/Interfaces/IKeyService.cs

@ -14,10 +14,9 @@ namespace Cloud_Manager.Models.Interfaces
/// <summary>
/// Generates an API Key based on the specified client
/// </summary>
/// <returns>A tokenized string</returns>
string GenerateKey(Contract a_clientContract, Databasemap a_database);
Task<bool> GenerateKey(Contract a_clientContract);
/// <summary>
///Returns the API if valid to return the related database id
///Returns the database Id if the API Key is valid to return the related database id
/// </summary>
/// <param name="a_Key"></param>
int? GetDatabaseIdFromKey(string a_Key);

135
Cloud_Manager/Models/ServiceRepo/TokenService.cs

@ -1,8 +1,10 @@
using Cloud_Manager.Models.ClientContractModels;
using Cloud_Manager.Models.Enums;
using Cloud_Manager.Models.Interfaces;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
@ -12,31 +14,152 @@ namespace Cloud_Manager.Models.ServiceRepo
public class TokenService : IKeyService
{
private IConfiguration m_configuration { get; }
private readonly Random m_random;
private BiskilogContext m_context;
public TokenService(IConfiguration a_configuration,BiskilogContext a_context)
public TokenService(IConfiguration a_configuration, BiskilogContext a_context)
{
m_configuration = a_configuration;
m_context = a_context;
m_random = new Random();
}
public AuthEnums ValidateKey(string a_Key)
{
throw new NotImplementedException();
if (!string.IsNullOrEmpty(a_Key))
{
Clientapikey? keyInfo = m_context.Clientapikeys.FirstOrDefault(k => k.Key == a_Key);
if (keyInfo != null)
{
if (keyInfo.IsActive == 0)
{
//Key is not active
return AuthEnums.Inactive;
}
public string GenerateKey(Contract a_clientContract, Databasemap a_database)
if (TryDecodeKey(a_Key, out int businessId))
{
Contract? contract = m_context.Contracts.FirstOrDefault(c => c.ContractId == keyInfo.ContractId && c.BusinessId == businessId && c.StartDate <= DateTime.Now && c.EndDate > DateTime.Now);
if (contract == null)
{
contract = m_context.Contracts.FirstOrDefault(c => c.ContractId == keyInfo.ContractId && c.BusinessId == businessId);
//If contract start date is not past the key should inactive
if (contract?.StartDate > DateTime.Now)
{
throw new NotImplementedException();
return AuthEnums.Inactive;
}
//Anyother reason contract is expired
return AuthEnums.Expired;
}
//Key is valid and contract not expired
return AuthEnums.Valid;
}
}
else
{
return AuthEnums.NotFound;
}
}
return AuthEnums.Invalid;
}
public async Task<bool> GenerateKey(Contract a_clientContract)
{
const string prefix = "AI";
const char delimiter = '@';
const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
StringBuilder key = new StringBuilder(32);
key.Append(prefix);
key.Append(a_clientContract.BusinessId);
key.Append(delimiter);
for (int i = key.Length; i < 32; i++)
{
key.Append(chars[m_random.Next(chars.Length)]);
}
Clientapikey clientapikey = new Clientapikey();
clientapikey.Key = key.ToString();
clientapikey.ContractId = a_clientContract.ContractId;
m_context.Clientapikeys.Add(clientapikey);
if (await m_context.SaveChangesAsync() > 0)
{
return true;
}
else
{
return false;
}
}
public int? GetDatabaseIdFromKey(string a_Key)
{
throw new NotImplementedException();
if (ValidateKey(a_Key) == AuthEnums.Valid)
{
if (TryDecodeKey(a_Key, out int businessId))
{
Clientapikey? keyInfo = m_context.Clientapikeys.FirstOrDefault(k => k.Key == a_Key);
Contract? contract = m_context.Contracts.FirstOrDefault(c => c.ContractId == keyInfo.ContractId && c.BusinessId == businessId && c.StartDate <= DateTime.Now && c.EndDate > DateTime.Now);
Databasemap? databaseMap = m_context.Databasemaps.FirstOrDefault(c => c.ClientId == contract.ClientId);
return databaseMap?.DbNo;
}
}
return null;
}
public string GetBaseBranch(string a_Key)
{
throw new NotImplementedException();
if (ValidateKey(a_Key) == AuthEnums.Valid)
{
if (TryDecodeKey(a_Key, out int businessId))
{
Clientapikey? keyInfo = m_context.Clientapikeys.FirstOrDefault(k => k.Key == a_Key);
Contract? contract = m_context.Contracts.FirstOrDefault(c => c.ContractId == keyInfo.ContractId && c.BusinessId == businessId && c.StartDate <= DateTime.Now && c.EndDate > DateTime.Now);
if (contract != null)
{
Clientbusiness? clientbusiness = m_context.Clientbusinesses.FirstOrDefault(cb => cb.ClientId == contract.ClientId && cb.BusinessId == businessId);
if (clientbusiness != null)
{
return clientbusiness.BusinessExternalId;
}
}
}
}
return String.Empty;
}
public static bool TryDecodeKey(string a_key, out int o_businessId)
{
char delimiter = '@';
o_businessId = 0;
// Check if the key has the expected length and starts with the expected prefix
if (a_key.Length == 32 && a_key.StartsWith("AI"))
{
// Find the index of the delimiter
int delimiterIndex = a_key.IndexOf(delimiter, 2);
// Check if the delimiter is found and there are characters after it
if (delimiterIndex != -1 && delimiterIndex < a_key.Length - 1)
{
// Attempt to parse the embedded integer value
if (int.TryParse(a_key.Substring(2, delimiterIndex - 2), out o_businessId))
{
return true; // Successfully decoded
}
}
}
return false; // Failed to decode
}
}
}

9
Cloud_Manager/Program.cs

@ -7,6 +7,10 @@ using Cloud_Manager.Models.Interfaces;
using Cloud_Manager;
using Cloud_Manager.Services;
using Cloud_Manager.Models.ServiceRepo;
using Cloud_Manager.Models.Enums;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Cloud_Manager.Middleware;
var builder = WebApplication.CreateBuilder(args);
@ -35,16 +39,17 @@ builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "SecureSwagger v1"));
app.UseHttpsRedirection();
app.UseKeyValidation();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();

Loading…
Cancel
Save