feat(AuthController): Login-Methode für Verbraucher-APIs hinzugefügt.

This commit is contained in:
Developer 02 2025-01-15 13:48:58 +01:00
parent 69efe28310
commit 79eaa06ed4
4 changed files with 56 additions and 16 deletions

View File

@ -11,6 +11,8 @@ using DigitalData.UserManager.Application.Contracts;
using DigitalData.UserManager.Application.DTOs.User; using DigitalData.UserManager.Application.DTOs.User;
using DigitalData.Core.Abstractions.Application; using DigitalData.Core.Abstractions.Application;
using System.Net; using System.Net;
using DigitalData.Auth.API.Dto;
using DigitalData.Auth.API.Services.Contracts;
namespace DigitalData.Auth.API.Controllers namespace DigitalData.Auth.API.Controllers
{ {
@ -20,6 +22,8 @@ namespace DigitalData.Auth.API.Controllers
{ {
private readonly IJwtSignatureHandler<UserReadDto> _userSignatureHandler; private readonly IJwtSignatureHandler<UserReadDto> _userSignatureHandler;
private readonly IJwtSignatureHandler<ConsumerApi> _apiSignatureHandler;
private readonly AuthApiParams _apiParams; private readonly AuthApiParams _apiParams;
private readonly ICryptoFactory _cryptoFactory; private readonly ICryptoFactory _cryptoFactory;
@ -30,7 +34,9 @@ namespace DigitalData.Auth.API.Controllers
private readonly IDirectorySearchService _dirSearchService; private readonly IDirectorySearchService _dirSearchService;
public AuthController(IJwtSignatureHandler<UserReadDto> userSignatureHandler, IOptions<AuthApiParams> cookieParamsOptions, ICryptoFactory cryptoFactory, ILogger<AuthController> logger, IUserService userService, IDirectorySearchService dirSearchService) private readonly IConsumerApiService _consumerApiService;
public AuthController(IJwtSignatureHandler<UserReadDto> userSignatureHandler, IOptions<AuthApiParams> cookieParamsOptions, ICryptoFactory cryptoFactory, ILogger<AuthController> logger, IUserService userService, IDirectorySearchService dirSearchService, IConsumerApiService consumerApiService, IJwtSignatureHandler<ConsumerApi> apiSignatureHandler)
{ {
_apiParams = cookieParamsOptions.Value; _apiParams = cookieParamsOptions.Value;
_userSignatureHandler = userSignatureHandler; _userSignatureHandler = userSignatureHandler;
@ -38,6 +44,8 @@ namespace DigitalData.Auth.API.Controllers
_logger = logger; _logger = logger;
_userService = userService; _userService = userService;
_dirSearchService = dirSearchService; _dirSearchService = dirSearchService;
_consumerApiService = consumerApiService;
_apiSignatureHandler = apiSignatureHandler;
} }
private async Task<IActionResult> CreateTokenAsync(LogInDto login, string consumerRoute, bool cookie = true) private async Task<IActionResult> CreateTokenAsync(LogInDto login, string consumerRoute, bool cookie = true)
@ -57,7 +65,8 @@ namespace DigitalData.Auth.API.Controllers
if (!_apiParams.Consumers.TryGetByRoute(consumerRoute, out var consumer)) if (!_apiParams.Consumers.TryGetByRoute(consumerRoute, out var consumer))
return Unauthorized(); return Unauthorized();
_cryptoFactory.TokenDescriptors.TryGet(_apiParams.Issuer, consumer.Audience, out var descriptor); if (!_cryptoFactory.TokenDescriptors.TryGet(_apiParams.Issuer, consumer.Audience, out var descriptor) || descriptor is null)
return StatusCode(StatusCodes.Status500InternalServerError);
var token = _userSignatureHandler.WriteToken(uRes.Data, descriptor); var token = _userSignatureHandler.WriteToken(uRes.Data, descriptor);
@ -71,10 +80,32 @@ namespace DigitalData.Auth.API.Controllers
return Ok(token); return Ok(token);
} }
private async Task<IActionResult> CreateTokenAsync(ConsumerApiLogin login, bool cookie = true)
{
if (!await _consumerApiService.VerifyAsync(login.Name, login.Password))
return Unauthorized();
var api = await _consumerApiService.ReadByNameAsync(login.Name);
if (!_cryptoFactory.TokenDescriptors.TryGet(_apiParams.Issuer, _apiParams.DefaultConsumer.Audience, out var descriptor) || descriptor is null)
return StatusCode(StatusCodes.Status500InternalServerError);
var token = _apiSignatureHandler!.WriteToken(api, descriptor);
//set cookie
if (cookie)
{
Response.Cookies.Append(_apiParams.CookieName, token, _apiParams.DefaultConsumer.CookieOptions.Create(lifetime: descriptor.Lifetime));
return Ok();
}
else
return Ok(token);
}
//TODO: Add role depends on group name //TODO: Add role depends on group name
[HttpPost("~/{consumerRoute}/login")] [HttpPost("~/{consumerRoute}/login")]
[AllowAnonymous] [AllowAnonymous]
public async Task<IActionResult> Login([FromBody] LogInDto login, string consumerRoute) public async Task<IActionResult> Login([FromForm] LogInDto login, [FromRoute] string consumerRoute)
{ {
try try
{ {
@ -87,6 +118,21 @@ namespace DigitalData.Auth.API.Controllers
} }
} }
[HttpPost("~/login")]
[AllowAnonymous]
public async Task<IActionResult> Login([FromForm] ConsumerApiLogin login)
{
try
{
return await CreateTokenAsync(login, true);
}
catch (Exception ex)
{
_logger.LogError(ex, "{Message}", ex.Message);
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPost("logout")] [HttpPost("logout")]
public IActionResult Logout() public IActionResult Logout()
{ {

View File

@ -14,6 +14,6 @@ namespace DigitalData.Auth.API.Services
public Task<ConsumerApi?> ReadByNameAsync(string name) => Task.Run(() => _consumerAPIs.FirstOrDefault(api => api.Name == name)); public Task<ConsumerApi?> ReadByNameAsync(string name) => Task.Run(() => _consumerAPIs.FirstOrDefault(api => api.Name == name));
public async Task<bool> VerifyAsync(ConsumerApiLogin login, string password) => (await ReadByNameAsync(login.Name))?.Password == password; public async Task<bool> VerifyAsync(string name, string password) => (await ReadByNameAsync(name))?.Password == password;
} }
} }

View File

@ -6,6 +6,6 @@ namespace DigitalData.Auth.API.Services.Contracts
{ {
public Task<ConsumerApi?> ReadByNameAsync(string name); public Task<ConsumerApi?> ReadByNameAsync(string name);
public Task<bool> VerifyAsync(ConsumerApiLogin login, string password); public Task<bool> VerifyAsync(string name, string password);
} }
} }

View File

@ -11,12 +11,7 @@
}, },
"DirectorySearchOptions": { "DirectorySearchOptions": {
"ServerName": "DD-VMP01-DC01", "ServerName": "DD-VMP01-DC01",
"Root": "DC=dd-gan,DC=local,DC=digitaldata,DC=works", "Root": "DC=dd-gan,DC=local,DC=digitaldata,DC=works"
"UserCacheExpirationDays": 1,
"CustomSearchFilters": {
"User": "(&(objectClass=user)(sAMAccountName=*))",
"Group": "(&(objectClass=group) (samAccountName=*))"
}
}, },
"Consumers": [ "Consumers": [
{ {
@ -25,7 +20,7 @@
}, },
{ {
"Route": "work-flow", "Route": "work-flow",
"Audience": "client.digitaldata.works" "Audience": "work-flow.digitaldata.works"
} }
], ],
"Issuer": "auth.digitaldata.works", "Issuer": "auth.digitaldata.works",
@ -44,22 +39,21 @@
"Issuer": "auth.digitaldata.works", "Issuer": "auth.digitaldata.works",
"Audience": "api.digitaldata.works", "Audience": "api.digitaldata.works",
"IsEncrypted": true, "IsEncrypted": true,
"ApiRoute": "api",
"Lifetime": "48:00:00" "Lifetime": "48:00:00"
}, },
{ {
"Id": "61c07d26-baa8-4cbb-bb33-ac4ee1838c3a", "Id": "61c07d26-baa8-4cbb-bb33-ac4ee1838c3a",
"Issuer": "auth.digitaldata.works", "Issuer": "auth.digitaldata.works",
"Audience": "client.digitaldata.works", "Audience": "work-flow.digitaldata.works",
"IsEncrypted": true, "IsEncrypted": true,
"ApiRoute": "client" "Lifetime": "02:00:00"
} }
] ]
}, },
"ConsumerAPIs": [ "ConsumerAPIs": [
{ {
"Name": "WorkFlow.API", "Name": "WorkFlow.API",
"Password": "t3B|aiJ'i-snLzNRj3B{9=&:lM5P@'i<EFBFBD>L" "Password": "t3B|aiJ'i-snLzNRj3B{9=&:lM5P@'iL"
}, },
{ {
"Name": "DigitalData.UserManager.API", "Name": "DigitalData.UserManager.API",