Compare commits
13 Commits
41151593fd
...
a325d07c6b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a325d07c6b | ||
|
|
69abd3afa2 | ||
|
|
cbdd6ee295 | ||
|
|
2c1abaaf32 | ||
|
|
8038ff74dd | ||
|
|
edcf3781b7 | ||
|
|
6ea053be36 | ||
|
|
67a62d7311 | ||
|
|
e17875dad7 | ||
|
|
b460de4e37 | ||
|
|
1ca336abe0 | ||
|
|
6e4a575864 | ||
|
|
d664adf000 |
14
WorkFlow.API/Attributes/ApiKeyAuthAttribute.cs
Normal file
14
WorkFlow.API/Attributes/ApiKeyAuthAttribute.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using WorkFlow.API.Filters;
|
||||
|
||||
namespace WorkFlow.API.Attributes
|
||||
{
|
||||
//TODO: move APIKeyAuthAttribute to Core.API
|
||||
public class APIKeyAuthAttribute : ServiceFilterAttribute
|
||||
{
|
||||
public APIKeyAuthAttribute()
|
||||
: base(typeof(APIKeyAuthFilter))
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -10,19 +10,16 @@ using DigitalData.Core.Abstractions.Application;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using DigitalData.Core.DTO;
|
||||
using WorkFlow.API.Models;
|
||||
using WorkFlow.API.Attributes;
|
||||
|
||||
namespace WorkFlow.API.Controllers
|
||||
{
|
||||
//TODO: implement up-to-date AuthController in UserManager
|
||||
[APIKeyAuth]
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class AuthController(IUserService userService, IGroupOfUserService gouService, IDirectorySearchService directorySearchService, IStringLocalizer<Resource> localizer, ILogger<AuthController> logger) : ControllerBase
|
||||
public class AuthController(IUserService userService, IDirectorySearchService dirSearchService, IStringLocalizer<Resource> localizer, ILogger<AuthController> logger) : ControllerBase
|
||||
{
|
||||
private readonly IUserService _userService = userService;
|
||||
private readonly IGroupOfUserService _gouService = gouService;
|
||||
private readonly IDirectorySearchService _dirSearchService = directorySearchService;
|
||||
private readonly IStringLocalizer<Resource> _localizer = localizer;
|
||||
private readonly ILogger<AuthController> _logger = logger;
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpGet("check")]
|
||||
public IActionResult CheckAuthentication()
|
||||
@ -33,78 +30,81 @@ namespace WorkFlow.API.Controllers
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[NonAction]
|
||||
public async Task<IActionResult> Login(UserReadDto user)
|
||||
{
|
||||
// Create claimsIdentity
|
||||
var claimsIdentity = new ClaimsIdentity(user.ToClaimList(), CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
|
||||
// Create authProperties
|
||||
var authProperties = new AuthenticationProperties
|
||||
{
|
||||
IsPersistent = true,
|
||||
AllowRefresh = true,
|
||||
ExpiresUtc = DateTime.UtcNow.AddMinutes(60)
|
||||
};
|
||||
|
||||
// Sign in
|
||||
await HttpContext.SignInAsync(
|
||||
CookieAuthenticationDefaults.AuthenticationScheme,
|
||||
new ClaimsPrincipal(claimsIdentity),
|
||||
authProperties);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpPost("login")]
|
||||
public async Task<IActionResult> Login([FromBody] Login login)
|
||||
{
|
||||
try
|
||||
{
|
||||
var username = string.Empty;
|
||||
DataResult<UserReadDto>? uRes = null;
|
||||
|
||||
if(login.Username is not null && login.UserId is not null)
|
||||
return BadRequest("Invalid request: either 'UserId' or 'Username' must be provided, but not both.");
|
||||
else if(login.Username is not null)
|
||||
username = login.Username;
|
||||
else if(login.UserId is int userId)
|
||||
{
|
||||
uRes = await _userService.ReadByIdAsync(userId);
|
||||
if (!uRes.IsSuccess || uRes.Data is null)
|
||||
{
|
||||
return Unauthorized(uRes);
|
||||
}
|
||||
}
|
||||
else
|
||||
return BadRequest("Invalid request: either 'UserId' or 'Username' must be provided, but not both.");
|
||||
|
||||
bool isValid = _dirSearchService.ValidateCredentials(username, login.Password);
|
||||
|
||||
if (!isValid)
|
||||
return Unauthorized(Result.Fail().Message(_localizer[Key.UserNotFound]));
|
||||
|
||||
var gouMsg = await _gouService.HasGroup(username, "PM_USER", caseSensitive: false);
|
||||
if (!gouMsg.IsSuccess)
|
||||
return Unauthorized(Result.Fail().Message(_localizer[Key.UnauthorizedUser]));
|
||||
|
||||
//find the user
|
||||
uRes ??= await _userService.ReadByUsernameAsync(username);
|
||||
if (!uRes.IsSuccess || uRes.Data is null)
|
||||
{
|
||||
_logger.LogNotice(uRes.Notices);
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
UserReadDto user = uRes.Data;
|
||||
|
||||
// Create claimsIdentity
|
||||
var claimsIdentity = new ClaimsIdentity(user.ToClaimList(), CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
|
||||
// Create authProperties
|
||||
var authProperties = new AuthenticationProperties
|
||||
{
|
||||
IsPersistent = true,
|
||||
AllowRefresh = true,
|
||||
ExpiresUtc = DateTime.UtcNow.AddMinutes(60)
|
||||
};
|
||||
|
||||
// Sign in
|
||||
await HttpContext.SignInAsync(
|
||||
CookieAuthenticationDefaults.AuthenticationScheme,
|
||||
new ClaimsPrincipal(claimsIdentity),
|
||||
authProperties);
|
||||
|
||||
_dirSearchService.SetSearchRootCache(user.Username, login.Password);
|
||||
|
||||
return Ok();
|
||||
return dirSearchService.ValidateCredentials(login.Username, login.Password)
|
||||
? await userService.ReadByUsernameAsync(login.Username).ThenAsync(
|
||||
SuccessAsync: Login,
|
||||
Fail: IActionResult (msg, ntc) =>
|
||||
{
|
||||
logger.LogNotice(ntc);
|
||||
logger.LogError("User could not be found, although verified by directory-search-service. It needs to be imported by UserManager. User name is {username}.", login.Username);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
})
|
||||
: Unauthorized(localizer[WFKey.UserNotFoundOrWrongPassword].Value);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpPost("login/{id}")]
|
||||
public async Task<IActionResult> LoginById([FromRoute] int id, [FromQuery] string password)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await userService.ReadByIdAsync(id).ThenAsync(
|
||||
SuccessAsync: async user
|
||||
=> dirSearchService.ValidateCredentials(user.Username, password)
|
||||
? await Login(user)
|
||||
: Unauthorized(localizer[WFKey.WrongPassword].Value),
|
||||
Fail: (msg, ntc) =>
|
||||
{
|
||||
if (ntc.HasFlag(Flag.NotFound))
|
||||
return Unauthorized(Key.UserNotFound);
|
||||
|
||||
logger.LogNotice(ntc);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
@ -121,16 +121,16 @@ namespace WorkFlow.API.Controllers
|
||||
if (string.IsNullOrEmpty(username))
|
||||
return Unauthorized();
|
||||
|
||||
return await _userService.ReadByUsernameAsync(username)
|
||||
return await userService.ReadByUsernameAsync(username)
|
||||
.ThenAsync(Ok, IActionResult (m, n) =>
|
||||
{
|
||||
_logger.LogNotice(n);
|
||||
return NotFound(Result.Fail().Message(_localizer[Key.UserNotFound]));
|
||||
logger.LogNotice(n);
|
||||
return NotFound(Result.Fail().Message(localizer[Key.UserNotFound].Value));
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
@ -146,7 +146,7 @@ namespace WorkFlow.API.Controllers
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
logger.LogError(ex, "{Message}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
using DigitalData.Core.API;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using WorkFlow.API.Attributes;
|
||||
using WorkFlow.Application.Contracts;
|
||||
using WorkFlow.Application.DTO.Config;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.API.Controllers
|
||||
{
|
||||
[APIKeyAuth]
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Security.Claims;
|
||||
using WorkFlow.API.Attributes;
|
||||
|
||||
namespace WorkFlow.API.Controllers
|
||||
{
|
||||
[APIKeyAuth]
|
||||
public static class ControllerExtensions
|
||||
{
|
||||
public static bool TryGetUserId(this ControllerBase controller, out int? id)
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
using DigitalData.Core.API;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using WorkFlow.API.Attributes;
|
||||
using WorkFlow.Application.Contracts;
|
||||
using WorkFlow.Application.DTO.Profile;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.API.Controllers
|
||||
{
|
||||
[APIKeyAuth]
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
|
||||
@ -2,12 +2,14 @@
|
||||
using DigitalData.Core.DTO;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using WorkFlow.API.Attributes;
|
||||
using WorkFlow.Application.Contracts;
|
||||
using WorkFlow.Application.DTO.ProfileControlsTF;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.API.Controllers
|
||||
{
|
||||
[APIKeyAuth]
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
|
||||
@ -2,12 +2,14 @@
|
||||
using DigitalData.Core.DTO;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using WorkFlow.API.Attributes;
|
||||
using WorkFlow.Application.Contracts;
|
||||
using WorkFlow.Application.DTO.ProfileObjState;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.API.Controllers
|
||||
{
|
||||
[APIKeyAuth]
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
using DigitalData.Core.API;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using WorkFlow.API.Attributes;
|
||||
using WorkFlow.Application.Contracts;
|
||||
using WorkFlow.Application.DTO.State;
|
||||
using WorkFlow.Domain.Entities;
|
||||
|
||||
namespace WorkFlow.API.Controllers
|
||||
{
|
||||
[APIKeyAuth]
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
|
||||
@ -2,9 +2,11 @@
|
||||
using DigitalData.UserManager.Application.Contracts;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using WorkFlow.API.Attributes;
|
||||
|
||||
namespace WorkFlow.API.Controllers
|
||||
{
|
||||
[APIKeyAuth]
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
|
||||
22
WorkFlow.API/Extensions/DIExtensions.cs
Normal file
22
WorkFlow.API/Extensions/DIExtensions.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using WorkFlow.API.Filters;
|
||||
using WorkFlow.API.Models;
|
||||
|
||||
namespace WorkFlow.API.Extensions
|
||||
{
|
||||
public static class DIExtensions
|
||||
{
|
||||
public static IServiceCollection AddAPIKeyAuth(this IServiceCollection services, Func<string?, bool> isValidKey, string headerName = "X-API-Key")
|
||||
=> services.AddSingleton<APIKeyAuthFilter>(provider => new(isValidKey: isValidKey, headerName: headerName));
|
||||
|
||||
public static IServiceCollection AddAPIKeyAuth(this IServiceCollection services, APIKeyAuthOptions options, bool configureOptions = true)
|
||||
{
|
||||
if(configureOptions)
|
||||
services.TryAddSingleton(Options.Create(options));
|
||||
|
||||
return services.AddAPIKeyAuth(isValidKey: key => options.Key is null || options.Key == key, headerName: options.HeaderName);
|
||||
}
|
||||
}
|
||||
}
|
||||
36
WorkFlow.API/Filters/APIKeyAuthHeaderOpFilter.cs
Normal file
36
WorkFlow.API/Filters/APIKeyAuthHeaderOpFilter.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.OpenApi.Any;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using WorkFlow.API.Models;
|
||||
|
||||
namespace WorkFlow.API.Filters
|
||||
{
|
||||
public class APIKeyAuthHeaderOpFilter(IOptions<APIKeyAuthOptions> options, IWebHostEnvironment environment) : IOperationFilter
|
||||
{
|
||||
private readonly APIKeyAuthOptions apiKeyAuthOptions = options.Value;
|
||||
|
||||
public void Apply(OpenApiOperation operation, OperationFilterContext context)
|
||||
{
|
||||
var param = new OpenApiParameter
|
||||
{
|
||||
Name = apiKeyAuthOptions.HeaderName,
|
||||
In = ParameterLocation.Header,
|
||||
Required = true,
|
||||
AllowEmptyValue = false,
|
||||
Schema = new OpenApiSchema
|
||||
{
|
||||
Type = "string"
|
||||
}
|
||||
};
|
||||
|
||||
if(environment.IsDevelopment())
|
||||
param.Schema.Default = new OpenApiString(apiKeyAuthOptions.Key);
|
||||
|
||||
if (apiKeyAuthOptions.SwaggerDescription is not null)
|
||||
param.Description = apiKeyAuthOptions.SwaggerDescription;
|
||||
|
||||
operation.Parameters.Add(param);
|
||||
}
|
||||
}
|
||||
}
|
||||
14
WorkFlow.API/Filters/ApiKeyAuthFilter.cs
Normal file
14
WorkFlow.API/Filters/ApiKeyAuthFilter.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace WorkFlow.API.Filters
|
||||
{
|
||||
public class APIKeyAuthFilter(Func<string?, bool> isValidKey, string headerName = "X-API-Key") : IAuthorizationFilter
|
||||
{
|
||||
public void OnAuthorization(AuthorizationFilterContext context)
|
||||
{
|
||||
if (!isValidKey(context.HttpContext.Request.Headers[headerName]))
|
||||
context.Result = new UnauthorizedResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
WorkFlow.API/Models/APIKeyAuthOptions.cs
Normal file
11
WorkFlow.API/Models/APIKeyAuthOptions.cs
Normal file
@ -0,0 +1,11 @@
|
||||
namespace WorkFlow.API.Models
|
||||
{
|
||||
public class APIKeyAuthOptions
|
||||
{
|
||||
public string? Key { get; init; } = null;
|
||||
|
||||
public string HeaderName { get; init; } = "X-API-Key";
|
||||
|
||||
public string? SwaggerDescription { get; init; } = null;
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
namespace WorkFlow.API.Models
|
||||
{
|
||||
public record Login(int? UserId, string? Username, string Password);
|
||||
public record Login(string Username, string Password);
|
||||
}
|
||||
@ -8,58 +8,93 @@ using DigitalData.Core.Application;
|
||||
using DigitalData.UserManager.Application.DTOs.User;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using WorkFlow.API.Models;
|
||||
using System.Security.Claims;
|
||||
using NLog;
|
||||
using NLog.Web;
|
||||
using WorkFlow.API.Extensions;
|
||||
using WorkFlow.API.Filters;
|
||||
using Microsoft.OpenApi.Models;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
var config = builder.Configuration;
|
||||
var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
|
||||
logger.Info("Logging initialized.");
|
||||
|
||||
// Add services to the container.
|
||||
var cnn_str = config.GetConnectionString("Default") ?? throw new ("Default connection string not found.");
|
||||
builder.Services.AddDbContext<WFDBContext>(options => options.UseSqlServer(cnn_str).EnableDetailedErrors());
|
||||
builder.Services.AddWorkFlow().AddUserManager<WFDBContext>();
|
||||
builder.Services.AddCookieBasedLocalizer();
|
||||
builder.ConfigureBySection<DirectorySearchOptions>();
|
||||
builder.Services.AddDirectorySearchService();
|
||||
builder.Services.AddJWTService<UserReadDto>(user => new SecurityTokenDescriptor()
|
||||
try
|
||||
{
|
||||
Claims = user.ToClaimList().ToDictionary(claim => claim.Type, claim => claim.Value as object)
|
||||
});
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
var config = builder.Configuration;
|
||||
|
||||
builder.Services.AddControllers();
|
||||
// Add NLogger
|
||||
builder.Logging.ClearProviders();
|
||||
builder.Host.UseNLog();
|
||||
|
||||
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
|
||||
.AddCookie(options =>
|
||||
// Add services to the container.
|
||||
var cnn_str = config.GetConnectionString("Default") ?? throw new("Default connection string not found.");
|
||||
builder.Services.AddDbContext<WFDBContext>(options => options.UseSqlServer(cnn_str).EnableDetailedErrors());
|
||||
builder.Services.AddWorkFlow().AddUserManager<WFDBContext>();
|
||||
builder.Services.AddCookieBasedLocalizer();
|
||||
builder.ConfigureBySection<DirectorySearchOptions>();
|
||||
builder.Services.AddDirectorySearchService();
|
||||
builder.Services.AddJWTService<UserReadDto>(user => new SecurityTokenDescriptor()
|
||||
{
|
||||
options.Cookie.HttpOnly = true; // Makes the cookie inaccessible to client-side scripts for security
|
||||
options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest; // Ensures cookies are sent over HTTPS only
|
||||
options.Cookie.SameSite = SameSiteMode.Strict; // Protects against CSRF attacks by restricting how cookies are sent with requests from external sites
|
||||
options.LoginPath = "/api/auth/login";
|
||||
options.LogoutPath = "/api/auth/logout";
|
||||
options.ExpireTimeSpan = TimeSpan.FromMinutes(60); // timeout.
|
||||
options.SlidingExpiration = true; //refreshes the expiration time on each request.
|
||||
options.Cookie.Name = "AuthSession";
|
||||
Claims = user.ToClaimList().ToDictionary(claim => claim.Type, claim => claim.Value as object)
|
||||
});
|
||||
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen();
|
||||
bool disableAPIKeyAuth = config.GetValue<bool>("DisableAPIKeyAuth") && builder.IsDevOrDiP();
|
||||
if (disableAPIKeyAuth)
|
||||
builder.Services.AddAPIKeyAuth(new APIKeyAuthOptions());
|
||||
else
|
||||
if (config.GetSection("APIKeyAuth").Get<APIKeyAuthOptions>() is APIKeyAuthOptions options)
|
||||
builder.Services.AddAPIKeyAuth(options);
|
||||
else
|
||||
throw new("The API Key Authorization configuration is not available in the app settings, even though the app is not in development or DiP mode and API Key Authorization is not disabled.");
|
||||
|
||||
var app = builder.Build();
|
||||
builder.Services.AddControllers();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.IsDevOrDiP() && app.Configuration.GetValue<bool>("EnableSwagger"))
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
|
||||
.AddCookie(options =>
|
||||
{
|
||||
options.Cookie.HttpOnly = true; // Makes the cookie inaccessible to client-side scripts for security
|
||||
options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest; // Ensures cookies are sent over HTTPS only
|
||||
options.Cookie.SameSite = SameSiteMode.Strict; // Protects against CSRF attacks by restricting how cookies are sent with requests from external sites
|
||||
options.LoginPath = "/api/auth/login";
|
||||
options.LogoutPath = "/api/auth/logout";
|
||||
options.ExpireTimeSpan = TimeSpan.FromMinutes(60); // timeout.
|
||||
options.SlidingExpiration = true; //refreshes the expiration time on each request.
|
||||
options.Cookie.Name = "AuthSession";
|
||||
});
|
||||
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen(setupAct =>
|
||||
{
|
||||
if(!disableAPIKeyAuth)
|
||||
setupAct.OperationFilter<APIKeyAuthHeaderOpFilter>();
|
||||
|
||||
if(config.GetSection("OpenApiInfo").Get<OpenApiInfo>() is OpenApiInfo openApiInfo)
|
||||
setupAct.SwaggerDoc(openApiInfo?.Version ?? "v1", openApiInfo);
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.IsDevOrDiP() && app.Configuration.GetValue<bool>("EnableSwagger"))
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseAuthentication();
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.UseCookieBasedLocalizer("de-DE");
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseAuthentication();
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.UseCookieBasedLocalizer("de-DE");
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error(ex, "Stopped program because of exception.");
|
||||
throw;
|
||||
}
|
||||
8
WorkFlow.API/WFKey.cs
Normal file
8
WorkFlow.API/WFKey.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace WorkFlow.API
|
||||
{
|
||||
public static class WFKey
|
||||
{
|
||||
public static readonly string WrongPassword = nameof(WrongPassword);
|
||||
public static readonly string UserNotFoundOrWrongPassword = nameof(UserNotFoundOrWrongPassword);
|
||||
}
|
||||
}
|
||||
@ -8,6 +8,8 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DigitalData.Core.API" Version="2.0.0" />
|
||||
<PackageReference Include="NLog" Version="5.3.4" />
|
||||
<PackageReference Include="NLog.Web.AspNetCore" Version="5.3.14" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@ -1,12 +1,56 @@
|
||||
{
|
||||
"DiPMode": true,
|
||||
"EnableSwagger": true,
|
||||
"DisableAPIKeyAuth": false,
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"NLog": {
|
||||
"throwConfigExceptions": true,
|
||||
"variables": {
|
||||
"logDirectory": "E:\\LogFiles\\Digital Data\\workFlow",
|
||||
"logFileNamePrefix": "${shortdate}-ECM.EnvelopeGenerator.Web"
|
||||
},
|
||||
"targets": {
|
||||
"infoLogs": {
|
||||
"type": "File",
|
||||
"fileName": "${logDirectory}\\${logFileNamePrefix}-Info.log",
|
||||
"maxArchiveDays": 30
|
||||
},
|
||||
"errorLogs": {
|
||||
"type": "File",
|
||||
"fileName": "${logDirectory}\\${logFileNamePrefix}-Error.log",
|
||||
"maxArchiveDays": 30
|
||||
},
|
||||
"criticalLogs": {
|
||||
"type": "File",
|
||||
"fileName": "${logDirectory}\\${logFileNamePrefix}-Critical.log",
|
||||
"maxArchiveDays": 30
|
||||
}
|
||||
},
|
||||
// Trace, Debug, Info, Warn, Error and *Fatal*
|
||||
"rules": [
|
||||
{
|
||||
"logger": "*",
|
||||
"minLevel": "Info",
|
||||
"maxLevel": "Warn",
|
||||
"writeTo": "infoLogs"
|
||||
},
|
||||
{
|
||||
"logger": "*",
|
||||
"level": "Error",
|
||||
"writeTo": "errorLogs"
|
||||
},
|
||||
{
|
||||
"logger": "*",
|
||||
"level": "Fatal",
|
||||
"writeTo": "criticalLogs"
|
||||
}
|
||||
]
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"ConnectionStrings": {
|
||||
"Default": "Server=SDD-VMP04-SQL17\\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=dd;Encrypt=false;TrustServerCertificate=True;"
|
||||
@ -19,5 +63,18 @@
|
||||
"User": "(&(objectClass=user)(sAMAccountName=*))",
|
||||
"Group": "(&(objectClass=group) (samAccountName=*))"
|
||||
}
|
||||
},
|
||||
"APIKeyAuth": {
|
||||
"Key": "ULbcOUiAXAoCXPviyCGtObZUGnrCHNgDmtNbQNpq5MOhB0EFQn18dObdQ93INNy8xIcnOPMJfEHqOotllELVrJ2R5AjqOfQszT2j00w215GanD3UiJGwFhwmdoNFsmNj",
|
||||
"HeaderName": "X-API-Key",
|
||||
"SwaggerDescription": "Required header for API key authentication. Enter a valid API key."
|
||||
},
|
||||
"OpenApiInfo": {
|
||||
"Title": "WorkFlow API",
|
||||
"Contact": {
|
||||
"Email": "info-flow@digitaldata.works",
|
||||
"Name": "Digital Data GmbH",
|
||||
"Url": "https://digitaldata.works/"
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user