Developer 02 8d0beab709 Refactoring der Projektabhängigkeiten und Aktualisierung von Program.cs
Verweise auf DigitalData.UserManager.Application und
DigitalData.UserManager.Domain in DigitalData.UserManager.API.csproj entfernt.
Ein Verweis auf DigitalData.UserManager.DependencyInjection
wurde hinzugefügt, um die Architektur zu rationalisieren und die Verwaltung von Abhängigkeiten zu verbessern.
Program.cs wurde aktualisiert, um den neuen Namespace für Dependency Injection
für ein verbessertes Service-Management aufzunehmen.
2025-04-16 11:45:50 +02:00

221 lines
8.4 KiB
C#

using Microsoft.EntityFrameworkCore;
using DigitalData.UserManager.Infrastructure.Repositories;
using DigitalData.UserManager.Application;
using DigitalData.Core.Application;
using Microsoft.AspNetCore.Authentication.Cookies;
using NLog.Web;
using NLog;
using DigitalData.Core.API;
using DigitalData.UserManager.API.Controllers;
using DigitalData.UserManager.Application.Services;
using Microsoft.Data.SqlClient;
using Newtonsoft.Json;
using Microsoft.IdentityModel.Tokens;
using DigitalData.UserManager.Application.DTOs.User;
using DigitalData.UserManager.API.Models;
using DigitalData.Auth.Client;
using DigitalData.UserManager.API;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Options;
using DigitalData.Core.Abstractions.Security.Extensions;
using Microsoft.OpenApi.Models;
using DigitalData.UserManager.DependencyInjection;
var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
logger.Debug("init main");
try {
var builder = WebApplication.CreateBuilder();
var config = builder.Configuration;
builder.Services.AddEncryptor(builder.Configuration.GetSection("EncryptionParameters"));
if (builder.Configuration.GetValue<bool>("RunAsWindowsService"))
builder.Host.UseWindowsService();
builder.Logging.ClearProviders();
builder.Host.UseNLog();
builder.Services.AddControllers(opt =>
{
opt.Conventions.Add(new RemoveIfControllerConvention()
.AndIf(c => c.ControllerName == nameof(EncryptionController).Replace("Controller", ""))
.AndIf(c => !config.GetValue<bool>("UseEncryptor")));
}).AddNewtonsoftJson(options =>
{
options.SerializerSettings.DateTimeZoneHandling = config.GetValue<DateTimeZoneHandling>("DateTimeZoneHandling");
});
if (builder.Configuration.GetValue<bool>("UseSwagger"))
{
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
}
builder.Services.AddControllers(opt =>
{
opt.Conventions.Add(new RemoveIfControllerConvention()
.AndIf(c => c.ControllerName == nameof(EncryptionController).Replace("Controller", ""))
.AndIf(c => !config.GetValue<bool>("UseEncryptor")));
});
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";
});
// Once the app is built, the password will be decrypted with Encryptor. lazy loading also acts as a call back method.
Lazy<string>? cnn_str = null;
builder.Services.AddDbContext<UserManagerDbContext>(options => options.UseSqlServer(cnn_str!.Value).EnableSensitiveDataLogging());
var allowedOrigins = builder.Configuration.GetSection("AllowedOrigins").Get<string[]>() ?? throw new InvalidOperationException("In appsettings there is no allowed origin.");
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "DefaultCorsPolicy",
builder =>
{
builder.WithOrigins(allowedOrigins)
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
});
});
//builder.Services.AddAutoMapper(typeof(DirectoryMappingProfile).Assembly);
builder.Services.AddUserManager<UserManagerDbContext>();
builder.ConfigureBySection<DirectorySearchOptions>();
builder.Services.AddDirectorySearchService(config.GetSection("DirectorySearchOptions"));
builder.Services.AddJWTService<UserReadDto>(user => new SecurityTokenDescriptor()
{
Claims = user.ToClaimList().ToDictionary(claim => claim.Type, claim => claim.Value as object)
});
var lazyProvider = new LazyServiceProvider();
builder.Services.AddAuthHubClient(config.GetSection("AuthClientParams"));
var authTokenKeys = config.GetSection(nameof(AuthTokenKeys)).Get<AuthTokenKeys>() ?? new();
builder.Services
.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(opt =>
{
opt.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKeyResolver = (token, securityToken, identifier, parameters) =>
{
var clientParams = lazyProvider.GetRequiredService<IOptions<ClientParams>>()?.Value;
var publicKey = clientParams!.PublicKeys.Get(authTokenKeys.Issuer, authTokenKeys.Audience);
return new List<SecurityKey>() { publicKey.SecurityKey };
},
ValidateIssuer = true,
ValidIssuer = authTokenKeys.Issuer,
ValidateAudience = true,
ValidAudience = authTokenKeys.Audience,
};
opt.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
// if there is no token read related cookie or query string
if (context.Token is null) // if there is no token
{
if (context.Request.Cookies.TryGetValue(authTokenKeys.Cookie, out var cookieToken) && cookieToken is not null)
context.Token = cookieToken;
else if (context.Request.Query.TryGetValue(authTokenKeys.QueryString, out var queryStrToken))
context.Token = queryStrToken;
}
return Task.CompletedTask;
}
};
});
builder.Services.AddSwaggerGen(setupAct =>
{
setupAct.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "JWT Authorization header using the Bearer scheme. Example: \"Bearer {token}\"",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
Scheme = "Bearer"
});
setupAct.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
Array.Empty<string>()
}
});
});
builder.Services.AddCookieBasedLocalizer();
var app = builder.Build();
lazyProvider.Factory = () => app.Services;
cnn_str = new(() =>
{
var encryptor = app.Services.GetRequiredService<Encryptor>();
var eCnnStr = config.GetConnectionString("UM_DEF") ?? throw new InvalidOperationException("Connection string 'DD_ECM_Connection' is missing from the configuration.");
SqlConnectionStringBuilder cnnStrBuilder = new(eCnnStr);
cnnStrBuilder.UserID = encryptor.Decrypt(cnnStrBuilder.UserID);
cnnStrBuilder.Password = encryptor.Decrypt(cnnStrBuilder.Password);
var dCnnStr = cnnStrBuilder.ConnectionString;
return dCnnStr;
});
app.UseCors("DefaultCorsPolicy");
if (builder.Configuration.GetValue<bool>("UseSwagger"))
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseCookieBasedLocalizer("de-DE", "en-US");
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.MapDefaultControllerRoute();
app.Run();
}
catch (Exception exception)
{
logger.Error(exception, "Stopped program because of exception");
throw;
}