Compare commits

...

11 Commits

Author SHA1 Message Date
Developer 02
41151593fd feat: JWT-Service mit Unterstützung für UserReadDto-Ansprüche hinzufügen
- ToClaimDictionary-Erweiterungsmethode hinzugefügt, um die Ansprüche von UserReadDto in ein Wörterbuch zu konvertieren.
- JWT-Service konfiguriert, um Tokens mit Ansprüchen aus UserReadDto zu generieren.
- JWT-Service in die Authentifizierungskonfiguration integriert.
2024-10-25 14:51:50 +02:00
Developer 02
730b218eb5 feat: Erweiterungsmethode hinzugefügt, um UserReadDto in Claims-Liste zu konvertieren 2024-10-25 14:41:06 +02:00
Developer 02
ee99d40fb1 refactor(ProfileControlsTFCreateDto): Entfernte id. 2024-10-25 12:24:07 +02:00
Developer 02
364036b9e4 feat(API): Authentifizierungs-Cookie aktualisiert.
- ExpireTimeSpan als 1 Stunde zugewiesen.
 - SlidingExpiration als wahre Stunde zugewiesen.
 - Cookie-Name als 'AuthSession' zugewiesen.
2024-10-25 12:23:34 +02:00
Developer 02
27f68df6d7 Chore: Optionen zur Aktivierung von Swagger über die appsettings.json in der Produktion hinzugefügt. 2024-10-25 11:30:40 +02:00
Developer 02
02a7120413 feat(Model): LoginDto in Login umbenennen 2024-10-25 11:13:48 +02:00
Developer 02
d61140c349 feat(API): Verzeichnis-Suchdienst hinzugefügt 2024-10-25 10:58:02 +02:00
Developer 02
ef91358c96 feat(API): Cookie-basierter Lokalisierer hinzugefügt. 2024-10-25 10:54:06 +02:00
Developer 02
f2ab2a9759 feat(auth): Verbesserung der Login-Logik mit erweiterter Validierung und Fehlerbehandlung
- Überprüfungen hinzugefügt, um sicherzustellen, dass entweder 'UserId' oder 'Username' angegeben ist, jedoch nicht beide.
- Fehlermeldungen verbessert, um eine bessere Klarheit zu gewährleisten.
- Benutzerabfrage-Logik in der Login-Methode refaktoriert, um vorhandene Benutzerdaten nach Möglichkeit zu nutzen.
- Konsistente Protokollierung von Hinweisen und Fehlern für eine bessere Nachverfolgbarkeit sichergestellt.
2024-10-25 10:24:27 +02:00
Developer 02
0495dc10de feat: Eigenschaften zu LogInDto für Validierung und Null-Prüfungen hinzugefügt 2024-10-25 09:43:22 +02:00
Developer 02
9c41e7bb18 feat(API.Models): DTO erstellt, um sich sowohl über id-password als auch über username password anzumelden 2024-10-25 09:36:47 +02:00
6 changed files with 80 additions and 20 deletions

View File

@@ -6,10 +6,10 @@ using DigitalData.UserManager.Application.Contracts;
using DigitalData.UserManager.Application.DTOs.User;
using Microsoft.AspNetCore.Authorization;
using DigitalData.UserManager.Application;
using DigitalData.UserManager.Application.DTOs.Auth;
using DigitalData.Core.Abstractions.Application;
using Microsoft.Extensions.Localization;
using DigitalData.Core.DTO;
using WorkFlow.API.Models;
namespace WorkFlow.API.Controllers
{
@@ -40,40 +40,49 @@ namespace WorkFlow.API.Controllers
[AllowAnonymous]
[HttpPost("login")]
public async Task<IActionResult> Login([FromBody] LogInDto login)
public async Task<IActionResult> Login([FromBody] Login login)
{
try
{
bool isValid = _dirSearchService.ValidateCredentials(login.Username, login.Password);
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(login.Username, "PM_USER", caseSensitive: false);
var gouMsg = await _gouService.HasGroup(username, "PM_USER", caseSensitive: false);
if (!gouMsg.IsSuccess)
return Unauthorized(Result.Fail().Message(_localizer[Key.UnauthorizedUser]));
//find the user
var uRes = await _userService.ReadByUsernameAsync(login.Username);
uRes ??= await _userService.ReadByUsernameAsync(username);
if (!uRes.IsSuccess || uRes.Data is null)
{
return Unauthorized(uRes);
_logger.LogNotice(uRes.Notices);
return Unauthorized();
}
UserReadDto user = uRes.Data;
// Create claims
var claims = new List<Claim>
{
new (ClaimTypes.NameIdentifier, user.Id.ToString()),
new (ClaimTypes.Name, user.Username),
new (ClaimTypes.Surname, user.Name ?? ""),
new (ClaimTypes.GivenName, user.Prename ?? ""),
new (ClaimTypes.Email, user.Email ?? "")
};
// Create claimsIdentity
var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
var claimsIdentity = new ClaimsIdentity(user.ToClaimList(), CookieAuthenticationDefaults.AuthenticationScheme);
// Create authProperties
var authProperties = new AuthenticationProperties

View File

@@ -0,0 +1,4 @@
namespace WorkFlow.API.Models
{
public record Login(int? UserId, string? Username, string Password);
}

View File

@@ -0,0 +1,18 @@
using DigitalData.UserManager.Application.DTOs.User;
using System.Security.Claims;
namespace WorkFlow.API.Models
{
public static class ModelExtensions
{
public static List<Claim> ToClaimList(this UserReadDto user) => [
new (ClaimTypes.NameIdentifier, user.Id.ToString()),
new (ClaimTypes.Name, user.Username),
new (ClaimTypes.Surname, user.Name ?? ""),
new (ClaimTypes.GivenName, user.Prename ?? ""),
new (ClaimTypes.Email, user.Email ?? "")
];
public static Dictionary<string, object> ToClaimDictionary(this UserReadDto user) => user.ToClaimList().ToDictionary(claim => claim.Type, claim => (object) claim.Value);
}
}

View File

@@ -3,6 +3,12 @@ using DigitalData.UserManager.Application;
using Microsoft.EntityFrameworkCore;
using WorkFlow.Infrastructure;
using Microsoft.AspNetCore.Authentication.Cookies;
using DigitalData.Core.API;
using DigitalData.Core.Application;
using DigitalData.UserManager.Application.DTOs.User;
using Microsoft.IdentityModel.Tokens;
using WorkFlow.API.Models;
using System.Security.Claims;
var builder = WebApplication.CreateBuilder(args);
var config = builder.Configuration;
@@ -11,6 +17,13 @@ var config = builder.Configuration;
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()
{
Claims = user.ToClaimList().ToDictionary(claim => claim.Type, claim => claim.Value as object)
});
builder.Services.AddControllers();
@@ -22,6 +35,9 @@ builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationSc
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();
@@ -30,7 +46,7 @@ builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
if (app.IsDevOrDiP() && app.Configuration.GetValue<bool>("EnableSwagger"))
{
app.UseSwagger();
app.UseSwaggerUI();
@@ -42,6 +58,8 @@ app.UseAuthentication();
app.UseAuthorization();
app.UseCookieBasedLocalizer("de-DE");
app.MapControllers();
app.Run();

View File

@@ -1,4 +1,6 @@
{
"DiPMode": true,
"EnableSwagger": true,
"Logging": {
"LogLevel": {
"Default": "Information",
@@ -7,6 +9,15 @@
},
"AllowedHosts": "*",
"ConnectionStrings": {
"Default": "Server=SDD-VMP04-SQL17\\DD_DEVELOP01;Database=DD_ECM;User Id=g+2edXEbMbujCUjh7INZRQ==;Password=Bz/n9pu8EyzlVqicaMRQGQ==;Encrypt=false;TrustServerCertificate=True;"
"Default": "Server=SDD-VMP04-SQL17\\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=dd;Encrypt=false;TrustServerCertificate=True;"
},
"DirectorySearchOptions": {
"ServerName": "DD-VMP01-DC01",
"Root": "DC=dd-gan,DC=local,DC=digitaldata,DC=works",
"UserCacheExpirationDays": 1,
"CustomSearchFilters": {
"User": "(&(objectClass=user)(sAMAccountName=*))",
"Group": "(&(objectClass=group) (samAccountName=*))"
}
}
}

View File

@@ -1,6 +1,6 @@
namespace WorkFlow.Application.DTO.ProfileControlsTF
{
public record ProfileControlsTFCreateDto(int Id,
public record ProfileControlsTFCreateDto(
int ProfileId,
int UserId,
long ObjId,