Some checks failed
Publish Container / publish (push) Has been cancelled
- Removed Entity Framework Core identity schema and related migrations. - Introduced MongoDB-based authentication service with user seeding functionality. - Updated Program.cs to configure authentication and authorization using cookies. - Created new Login.razor component for user login interface. - Added RedirectToLogin component for handling unauthorized access. - Updated Dockerfile and docker-compose files for development and production environments. - Removed SQLite connection strings and related configurations. - Added MongoDB connection settings in appsettings.json and Docker configurations. - Implemented IMongoAuthService interface and MongoAuthService class for user management. - Created MongoAuthUser model for MongoDB user representation.
135 lines
4.6 KiB
C#
135 lines
4.6 KiB
C#
using System.Globalization;
|
|
using System.Security.Claims;
|
|
using Microsoft.AspNetCore.Authentication;
|
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
|
using Microsoft.AspNetCore.Components.Authorization;
|
|
using Microsoft.AspNetCore.Localization;
|
|
using Microsoft.Extensions.Options;
|
|
using MongoDB.Driver;
|
|
using WorkTracker.Components;
|
|
using WorkTracker.Configuration;
|
|
using WorkTracker.Services.Auth;
|
|
using WorkTracker.Services.Festivities;
|
|
using WorkTracker.Services.Settings;
|
|
|
|
var builder = WebApplication.CreateBuilder(args);
|
|
|
|
// Add services to the container.
|
|
builder.Services.AddRazorComponents()
|
|
.AddInteractiveServerComponents();
|
|
|
|
builder.Services.AddCascadingAuthenticationState();
|
|
builder.Services.AddAuthorization();
|
|
|
|
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
|
|
.AddCookie(options =>
|
|
{
|
|
options.LoginPath = "/login";
|
|
options.LogoutPath = "/logout";
|
|
options.AccessDeniedPath = "/login";
|
|
options.SlidingExpiration = true;
|
|
options.ExpireTimeSpan = TimeSpan.FromDays(14);
|
|
});
|
|
|
|
builder.Services.AddLocalization();
|
|
|
|
builder.Services.Configure<MongoDbOptions>(builder.Configuration.GetSection(MongoDbOptions.SectionName));
|
|
builder.Services.Configure<SingleUserOptions>(builder.Configuration.GetSection(SingleUserOptions.SectionName));
|
|
|
|
builder.Services.AddSingleton<IMongoClient>(sp =>
|
|
{
|
|
var options = sp.GetRequiredService<IOptions<MongoDbOptions>>().Value;
|
|
return new MongoClient(options.ConnectionString);
|
|
});
|
|
|
|
builder.Services.AddSingleton(sp =>
|
|
{
|
|
var options = sp.GetRequiredService<IOptions<MongoDbOptions>>().Value;
|
|
var mongoClient = sp.GetRequiredService<IMongoClient>();
|
|
return mongoClient.GetDatabase(options.DatabaseName);
|
|
});
|
|
|
|
builder.Services.AddScoped<IAppSettingsService, MongoAppSettingsService>();
|
|
builder.Services.AddSingleton<IMongoAuthService, MongoAuthService>();
|
|
builder.Services.AddSingleton<IItalianFestivitySource, ItalianFestivitySource>();
|
|
builder.Services.AddHostedService<SingleUserSeedService>();
|
|
|
|
var app = builder.Build();
|
|
|
|
var italianCulture = new CultureInfo("it-IT");
|
|
CultureInfo.DefaultThreadCurrentCulture = italianCulture;
|
|
CultureInfo.DefaultThreadCurrentUICulture = italianCulture;
|
|
|
|
var localizationOptions = new RequestLocalizationOptions
|
|
{
|
|
DefaultRequestCulture = new RequestCulture(italianCulture),
|
|
SupportedCultures = [italianCulture],
|
|
SupportedUICultures = [italianCulture]
|
|
};
|
|
|
|
// Configure the HTTP request pipeline.
|
|
if (!app.Environment.IsDevelopment())
|
|
{
|
|
app.UseExceptionHandler("/Error", createScopeForErrors: true);
|
|
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
|
app.UseHsts();
|
|
}
|
|
|
|
var useHttpsRedirection = app.Configuration.GetValue("UseHttpsRedirection", !app.Environment.IsDevelopment());
|
|
if (useHttpsRedirection)
|
|
{
|
|
app.UseHttpsRedirection();
|
|
}
|
|
|
|
app.UseRequestLocalization(localizationOptions);
|
|
|
|
app.UseAuthentication();
|
|
app.UseAuthorization();
|
|
|
|
app.UseAntiforgery();
|
|
|
|
app.MapPost("/login", async (HttpContext context, IMongoAuthService authService) =>
|
|
{
|
|
var form = await context.Request.ReadFormAsync();
|
|
var email = form["email"].ToString();
|
|
var password = form["password"].ToString();
|
|
var returnUrl = form["returnUrl"].ToString();
|
|
|
|
if (string.IsNullOrWhiteSpace(email) || string.IsNullOrWhiteSpace(password))
|
|
{
|
|
return TypedResults.LocalRedirect($"/login?error=Missing%20credentials&returnUrl={Uri.EscapeDataString(returnUrl)}");
|
|
}
|
|
|
|
var user = await authService.ValidateCredentialsAsync(email, password, context.RequestAborted);
|
|
if (user is null)
|
|
{
|
|
return TypedResults.LocalRedirect($"/login?error=Invalid%20credentials&returnUrl={Uri.EscapeDataString(returnUrl)}");
|
|
}
|
|
|
|
var claims = new List<Claim>
|
|
{
|
|
new(ClaimTypes.NameIdentifier, user.Id),
|
|
new(ClaimTypes.Name, user.Email)
|
|
};
|
|
|
|
var principal = new ClaimsPrincipal(new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme));
|
|
await context.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);
|
|
|
|
var safeReturnUrl = string.IsNullOrWhiteSpace(returnUrl) || !Uri.IsWellFormedUriString(returnUrl, UriKind.Relative)
|
|
? "/"
|
|
: returnUrl;
|
|
|
|
return TypedResults.LocalRedirect(safeReturnUrl);
|
|
}).DisableAntiforgery();
|
|
|
|
app.MapPost("/logout", async (HttpContext context) =>
|
|
{
|
|
await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
|
return TypedResults.LocalRedirect("/login");
|
|
}).DisableAntiforgery();
|
|
|
|
app.MapStaticAssets();
|
|
app.MapRazorComponents<App>()
|
|
.AddInteractiveServerRenderMode();
|
|
|
|
app.Run();
|