Die Cookie-basierte Autorisierung wurde mit DirectorySearchService eingerichtet.
This commit is contained in:
111
EnvelopeGenerator.GeneratorAPI/Controllers/AuthController.cs
Normal file
111
EnvelopeGenerator.GeneratorAPI/Controllers/AuthController.cs
Normal file
@@ -0,0 +1,111 @@
|
||||
using DigitalData.Core.Contracts.Application;
|
||||
using DigitalData.Core.DTO;
|
||||
using DigitalData.UserManager.Application.Contracts;
|
||||
using DigitalData.UserManager.Application.DTOs.User;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using System.Security.Claims;
|
||||
using DigitalData.UserManager.Application.DTOs.Auth;
|
||||
using DigitalData.UserManager.Application;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace EnvelopeGenerator.GeneratorAPI.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class AuthController : ControllerBase
|
||||
{
|
||||
private readonly ILogger<AuthController> _logger;
|
||||
private readonly IUserService _userService;
|
||||
private readonly IDirectorySearchService _dirSearchService;
|
||||
private readonly IStringLocalizer<Resource> _localizer;
|
||||
|
||||
public AuthController(ILogger<AuthController> logger, IUserService userService, IDirectorySearchService dirSearchService, IStringLocalizer<Resource> localizer)
|
||||
{
|
||||
_logger = logger;
|
||||
_userService = userService;
|
||||
_dirSearchService = dirSearchService;
|
||||
_localizer = localizer;
|
||||
}
|
||||
|
||||
//TODO: When a user group is created for signFlow, add a process to check if the user is in this group (like "PM_USER")
|
||||
[HttpPost("login")]
|
||||
public async Task<IActionResult> Login([FromBody] LogInDto login)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool isValid = _dirSearchService.ValidateCredentials(login.Username, login.Password);
|
||||
|
||||
if (!isValid)
|
||||
return Unauthorized(Result.Fail().Message(_localizer[Key.UserNotFound]));
|
||||
|
||||
//find the user
|
||||
var uRes = await _userService.ReadByUsernameAsync(login.Username);
|
||||
if (!uRes.IsSuccess || uRes.Data is null)
|
||||
{
|
||||
return Unauthorized(uRes);
|
||||
}
|
||||
|
||||
UserReadDto user = uRes.Data;
|
||||
|
||||
// Create claims
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new (ClaimTypes.NameIdentifier, user.Guid.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);
|
||||
|
||||
// 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();
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Unexpected error occurred.\n{ErrorMessage}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[Authorize]
|
||||
[HttpPost("logout")]
|
||||
public async Task<IActionResult> Logout()
|
||||
{
|
||||
try
|
||||
{
|
||||
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
return Ok();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Unexpected error occurred.\n{ErrorMessage}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpGet("check")]
|
||||
public IActionResult IsAuthenticated() => Ok(User.Identity?.IsAuthenticated ?? false);
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.GeneratorAPI.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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,10 +9,40 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.15" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||
<PackageReference Include="System.DirectoryServices" Version="7.0.1" />
|
||||
<PackageReference Include="System.DirectoryServices.AccountManagement" Version="7.0.1" />
|
||||
<PackageReference Include="System.DirectoryServices.Protocols" Version="7.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="ClientApp\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\EnvelopeGenerator.Application\EnvelopeGenerator.Application.csproj" />
|
||||
<ProjectReference Include="..\EnvelopeGenerator.Domain\EnvelopeGenerator.Domain.csproj" />
|
||||
<ProjectReference Include="..\EnvelopeGenerator.Infrastructure\EnvelopeGenerator.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="DigitalData.Core.API">
|
||||
<HintPath>..\..\WebCoreModules\DigitalData.Core.API\bin\Debug\net7.0\DigitalData.Core.API.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="DigitalData.Core.Application">
|
||||
<HintPath>..\..\WebCoreModules\DigitalData.Core.Application\bin\Debug\net7.0\DigitalData.Core.Application.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="DigitalData.Core.Contracts">
|
||||
<HintPath>..\..\WebCoreModules\DigitalData.Core.API\bin\Debug\net7.0\DigitalData.Core.Contracts.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="DigitalData.Core.DTO">
|
||||
<HintPath>..\..\WebCoreModules\DigitalData.Core.API\bin\Debug\net7.0\DigitalData.Core.DTO.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="DigitalData.Core.Infrastructure">
|
||||
<HintPath>..\..\WebCoreModules\DigitalData.Core.Infrastructure\bin\Debug\net7.0\DigitalData.Core.Infrastructure.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="DigitalData.UserManager.Application">
|
||||
<HintPath>..\..\WebUserManager\DigitalData.UserManager.Application\bin\Debug\net7.0\DigitalData.UserManager.Application.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,12 +1,45 @@
|
||||
using DigitalData.Core.API;
|
||||
using DigitalData.Core.Application;
|
||||
using DigitalData.UserManager.Application;
|
||||
using DigitalData.UserManager.Infrastructure.Repositories;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
var config = builder.Configuration;
|
||||
|
||||
builder.Services.AddControllers();
|
||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||
|
||||
// Swagger
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen();
|
||||
|
||||
// DbContext
|
||||
var connStr = config.GetConnectionString("Default") ?? throw new InvalidOperationException("There is no default connection string in appsettings.json.");
|
||||
builder.Services.AddDbContext<EGDbContext>(options => options.UseSqlServer(connStr));
|
||||
|
||||
// Authentication
|
||||
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";
|
||||
});
|
||||
|
||||
// User manager
|
||||
builder.Services.AddUserManager<EGDbContext>();
|
||||
|
||||
// LDAP
|
||||
builder.ConfigureBySection<DirectorySearchOptions>();
|
||||
builder.Services.AddDirectorySearchService();
|
||||
|
||||
// Localizer
|
||||
builder.Services.AddCookieBasedLocalizer() ;
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
@@ -16,12 +49,16 @@ if (app.Environment.IsDevelopment())
|
||||
app.UseSwaggerUI();
|
||||
}
|
||||
|
||||
// Localizer
|
||||
app.UseCookieBasedLocalizer("de-DE", "en-US");
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseDefaultFiles();
|
||||
app.UseStaticFiles();
|
||||
|
||||
app.UseAuthorization();
|
||||
app.UseAuthentication();
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
namespace EnvelopeGenerator.GeneratorAPI
|
||||
{
|
||||
public class WeatherForecast
|
||||
{
|
||||
public DateOnly Date { get; set; }
|
||||
|
||||
public int TemperatureC { get; set; }
|
||||
|
||||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
||||
|
||||
public string? Summary { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -5,5 +5,17 @@
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
"AllowedHosts": "*",
|
||||
"ConnectionStrings": {
|
||||
"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=*))"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user