Membership

This commit is contained in:
2025-12-01 15:15:05 +01:00
parent b1bd4f01b6
commit 06321840a8
32 changed files with 1546 additions and 141 deletions

View File

@ -0,0 +1,8 @@
using Microsoft.AspNetCore.Identity;
namespace StandManager.Domain.Entita;
// Add profile data for application users by adding properties to the ApplicationUser class
public class ApplicationUser : IdentityUser
{
}

View File

@ -8,11 +8,13 @@
<ItemGroup> <ItemGroup>
<SupportedPlatform Include="browser"/> <SupportedPlatform Include="browser" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.21"/> <PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.21" />
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.3.1" />
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="9.0.11" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,4 +1,5 @@
using Microsoft.EntityFrameworkCore; using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using OAService.Infrastructure.DAL.Context; using OAService.Infrastructure.DAL.Context;
using StandManager.Domain.Entita; using StandManager.Domain.Entita;

View File

@ -0,0 +1,147 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using StandManager.Infrastructure.DAL.Context;
#nullable disable
namespace StandManager.Infrastructure.Migrations
{
[DbContext(typeof(StandManagerDbContext))]
[Migration("20251201110046_Initial")]
partial class Initial
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.11")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("StandManager.Domain.Entita.ApplicationUser", b =>
{
b.Property<string>("Id")
.HasColumnType("nvarchar(450)");
b.Property<int>("AccessFailedCount")
.HasColumnType("int");
b.Property<string>("ConcurrencyStamp")
.HasColumnType("nvarchar(max)");
b.Property<string>("Email")
.HasColumnType("nvarchar(max)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("bit");
b.Property<bool>("LockoutEnabled")
.HasColumnType("bit");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("datetimeoffset");
b.Property<string>("NormalizedEmail")
.HasColumnType("nvarchar(max)");
b.Property<string>("NormalizedUserName")
.HasColumnType("nvarchar(max)");
b.Property<string>("PasswordHash")
.HasColumnType("nvarchar(max)");
b.Property<string>("PhoneNumber")
.HasColumnType("nvarchar(max)");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("bit");
b.Property<string>("SecurityStamp")
.HasColumnType("nvarchar(max)");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("bit");
b.Property<string>("UserName")
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("ApplicationUsers");
});
modelBuilder.Entity("StandManager.Domain.Entita.Utente", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<string>("Cognome")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<DateTime>("DataCreazione")
.HasColumnType("datetime2");
b.Property<DateTime?>("DataModifica")
.HasColumnType("datetime2");
b.Property<bool>("Eliminato")
.HasColumnType("bit");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<Guid?>("IdUtenteCreazione")
.HasColumnType("uniqueidentifier");
b.Property<Guid?>("IdUtenteModifica")
.HasColumnType("uniqueidentifier");
b.Property<string>("Nome")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Username")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.HasIndex("IdUtenteCreazione");
b.HasIndex("IdUtenteModifica");
b.ToTable("Utente");
});
modelBuilder.Entity("StandManager.Domain.Entita.Utente", b =>
{
b.HasOne("StandManager.Domain.Entita.Utente", "UtenteCreazione")
.WithMany()
.HasForeignKey("IdUtenteCreazione");
b.HasOne("StandManager.Domain.Entita.Utente", "UtenteModifica")
.WithMany()
.HasForeignKey("IdUtenteModifica");
b.Navigation("UtenteCreazione");
b.Navigation("UtenteModifica");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,91 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace StandManager.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class Initial : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "ApplicationUsers",
columns: table => new
{
Id = table.Column<string>(type: "nvarchar(450)", nullable: false),
UserName = table.Column<string>(type: "nvarchar(max)", nullable: true),
NormalizedUserName = table.Column<string>(type: "nvarchar(max)", nullable: true),
Email = table.Column<string>(type: "nvarchar(max)", nullable: true),
NormalizedEmail = table.Column<string>(type: "nvarchar(max)", nullable: true),
EmailConfirmed = table.Column<bool>(type: "bit", nullable: false),
PasswordHash = table.Column<string>(type: "nvarchar(max)", nullable: true),
SecurityStamp = table.Column<string>(type: "nvarchar(max)", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(max)", nullable: true),
PhoneNumber = table.Column<string>(type: "nvarchar(max)", nullable: true),
PhoneNumberConfirmed = table.Column<bool>(type: "bit", nullable: false),
TwoFactorEnabled = table.Column<bool>(type: "bit", nullable: false),
LockoutEnd = table.Column<DateTimeOffset>(type: "datetimeoffset", nullable: true),
LockoutEnabled = table.Column<bool>(type: "bit", nullable: false),
AccessFailedCount = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ApplicationUsers", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Utente",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Username = table.Column<string>(type: "nvarchar(max)", nullable: false),
Email = table.Column<string>(type: "nvarchar(max)", nullable: false),
Password = table.Column<string>(type: "nvarchar(max)", nullable: false),
Nome = table.Column<string>(type: "nvarchar(max)", nullable: false),
Cognome = table.Column<string>(type: "nvarchar(max)", nullable: false),
DataCreazione = table.Column<DateTime>(type: "datetime2", nullable: false),
DataModifica = table.Column<DateTime>(type: "datetime2", nullable: true),
Eliminato = table.Column<bool>(type: "bit", nullable: false),
IdUtenteCreazione = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
IdUtenteModifica = table.Column<Guid>(type: "uniqueidentifier", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Utente", x => x.Id);
table.ForeignKey(
name: "FK_Utente_Utente_IdUtenteCreazione",
column: x => x.IdUtenteCreazione,
principalTable: "Utente",
principalColumn: "Id");
table.ForeignKey(
name: "FK_Utente_Utente_IdUtenteModifica",
column: x => x.IdUtenteModifica,
principalTable: "Utente",
principalColumn: "Id");
});
migrationBuilder.CreateIndex(
name: "IX_Utente_IdUtenteCreazione",
table: "Utente",
column: "IdUtenteCreazione");
migrationBuilder.CreateIndex(
name: "IX_Utente_IdUtenteModifica",
table: "Utente",
column: "IdUtenteModifica");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "ApplicationUsers");
migrationBuilder.DropTable(
name: "Utente");
}
}
}

View File

@ -0,0 +1,253 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using StandManager.Infrastructure.DAL.Context;
#nullable disable
namespace StandManager.Infrastructure.Migrations
{
[DbContext(typeof(StandManagerDbContext))]
[Migration("20251201115553_UserApp")]
partial class UserApp
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.11")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("nvarchar(max)");
b.Property<string>("ClaimValue")
.HasColumnType("nvarchar(max)");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("nvarchar(450)");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("nvarchar(450)");
b.Property<string>("ProviderKey")
.HasColumnType("nvarchar(450)");
b.Property<string>("ProviderDisplayName")
.HasColumnType("nvarchar(max)");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("nvarchar(450)");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("nvarchar(450)");
b.Property<string>("LoginProvider")
.HasColumnType("nvarchar(450)");
b.Property<string>("Name")
.HasColumnType("nvarchar(450)");
b.Property<string>("Value")
.HasColumnType("nvarchar(max)");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("StandManager.Domain.Entita.ApplicationUser", b =>
{
b.Property<string>("Id")
.HasColumnType("nvarchar(450)");
b.Property<int>("AccessFailedCount")
.HasColumnType("int");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("nvarchar(max)");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("bit");
b.Property<bool>("LockoutEnabled")
.HasColumnType("bit");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("datetimeoffset");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("PasswordHash")
.HasColumnType("nvarchar(max)");
b.Property<string>("PhoneNumber")
.HasColumnType("nvarchar(max)");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("bit");
b.Property<string>("SecurityStamp")
.HasColumnType("nvarchar(max)");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("bit");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex")
.HasFilter("[NormalizedUserName] IS NOT NULL");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("StandManager.Domain.Entita.Utente", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<string>("Cognome")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<DateTime>("DataCreazione")
.HasColumnType("datetime2");
b.Property<DateTime?>("DataModifica")
.HasColumnType("datetime2");
b.Property<bool>("Eliminato")
.HasColumnType("bit");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<Guid?>("IdUtenteCreazione")
.HasColumnType("uniqueidentifier");
b.Property<Guid?>("IdUtenteModifica")
.HasColumnType("uniqueidentifier");
b.Property<string>("Nome")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Username")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.HasIndex("IdUtenteCreazione");
b.HasIndex("IdUtenteModifica");
b.ToTable("Utente");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("StandManager.Domain.Entita.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("StandManager.Domain.Entita.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("StandManager.Domain.Entita.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("StandManager.Domain.Entita.Utente", b =>
{
b.HasOne("StandManager.Domain.Entita.Utente", "UtenteCreazione")
.WithMany()
.HasForeignKey("IdUtenteCreazione");
b.HasOne("StandManager.Domain.Entita.Utente", "UtenteModifica")
.WithMany()
.HasForeignKey("IdUtenteModifica");
b.Navigation("UtenteCreazione");
b.Navigation("UtenteModifica");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,224 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace StandManager.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class UserApp : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropPrimaryKey(
name: "PK_ApplicationUsers",
table: "ApplicationUsers");
migrationBuilder.RenameTable(
name: "ApplicationUsers",
newName: "AspNetUsers");
migrationBuilder.AlterColumn<string>(
name: "UserName",
table: "AspNetUsers",
type: "nvarchar(256)",
maxLength: 256,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(max)",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "NormalizedUserName",
table: "AspNetUsers",
type: "nvarchar(256)",
maxLength: 256,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(max)",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "NormalizedEmail",
table: "AspNetUsers",
type: "nvarchar(256)",
maxLength: 256,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(max)",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Email",
table: "AspNetUsers",
type: "nvarchar(256)",
maxLength: 256,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(max)",
oldNullable: true);
migrationBuilder.AddPrimaryKey(
name: "PK_AspNetUsers",
table: "AspNetUsers",
column: "Id");
migrationBuilder.CreateTable(
name: "AspNetUserClaims",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
UserId = table.Column<string>(type: "nvarchar(450)", nullable: false),
ClaimType = table.Column<string>(type: "nvarchar(max)", nullable: true),
ClaimValue = table.Column<string>(type: "nvarchar(max)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserLogins",
columns: table => new
{
LoginProvider = table.Column<string>(type: "nvarchar(450)", nullable: false),
ProviderKey = table.Column<string>(type: "nvarchar(450)", nullable: false),
ProviderDisplayName = table.Column<string>(type: "nvarchar(max)", nullable: true),
UserId = table.Column<string>(type: "nvarchar(450)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
table.ForeignKey(
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserTokens",
columns: table => new
{
UserId = table.Column<string>(type: "nvarchar(450)", nullable: false),
LoginProvider = table.Column<string>(type: "nvarchar(450)", nullable: false),
Name = table.Column<string>(type: "nvarchar(450)", nullable: false),
Value = table.Column<string>(type: "nvarchar(max)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
table.ForeignKey(
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "EmailIndex",
table: "AspNetUsers",
column: "NormalizedEmail");
migrationBuilder.CreateIndex(
name: "UserNameIndex",
table: "AspNetUsers",
column: "NormalizedUserName",
unique: true,
filter: "[NormalizedUserName] IS NOT NULL");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserClaims_UserId",
table: "AspNetUserClaims",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserLogins_UserId",
table: "AspNetUserLogins",
column: "UserId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AspNetUserClaims");
migrationBuilder.DropTable(
name: "AspNetUserLogins");
migrationBuilder.DropTable(
name: "AspNetUserTokens");
migrationBuilder.DropPrimaryKey(
name: "PK_AspNetUsers",
table: "AspNetUsers");
migrationBuilder.DropIndex(
name: "EmailIndex",
table: "AspNetUsers");
migrationBuilder.DropIndex(
name: "UserNameIndex",
table: "AspNetUsers");
migrationBuilder.RenameTable(
name: "AspNetUsers",
newName: "ApplicationUsers");
migrationBuilder.AlterColumn<string>(
name: "UserName",
table: "ApplicationUsers",
type: "nvarchar(max)",
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(256)",
oldMaxLength: 256,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "NormalizedUserName",
table: "ApplicationUsers",
type: "nvarchar(max)",
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(256)",
oldMaxLength: 256,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "NormalizedEmail",
table: "ApplicationUsers",
type: "nvarchar(max)",
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(256)",
oldMaxLength: 256,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Email",
table: "ApplicationUsers",
type: "nvarchar(max)",
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(256)",
oldMaxLength: 256,
oldNullable: true);
migrationBuilder.AddPrimaryKey(
name: "PK_ApplicationUsers",
table: "ApplicationUsers",
column: "Id");
}
}
}

View File

@ -0,0 +1,95 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using StandManager.Infrastructure.DAL.Context;
#nullable disable
namespace StandManager.Infrastructure.Migrations
{
[DbContext(typeof(StandManagerDbContext))]
[Migration("20251201141435_removedUser")]
partial class removedUser
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.11")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("StandManager.Domain.Entita.Utente", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<string>("Cognome")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<DateTime>("DataCreazione")
.HasColumnType("datetime2");
b.Property<DateTime?>("DataModifica")
.HasColumnType("datetime2");
b.Property<bool>("Eliminato")
.HasColumnType("bit");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<Guid?>("IdUtenteCreazione")
.HasColumnType("uniqueidentifier");
b.Property<Guid?>("IdUtenteModifica")
.HasColumnType("uniqueidentifier");
b.Property<string>("Nome")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Username")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.HasIndex("IdUtenteCreazione");
b.HasIndex("IdUtenteModifica");
b.ToTable("Utente");
});
modelBuilder.Entity("StandManager.Domain.Entita.Utente", b =>
{
b.HasOne("StandManager.Domain.Entita.Utente", "UtenteCreazione")
.WithMany()
.HasForeignKey("IdUtenteCreazione");
b.HasOne("StandManager.Domain.Entita.Utente", "UtenteModifica")
.WithMany()
.HasForeignKey("IdUtenteModifica");
b.Navigation("UtenteCreazione");
b.Navigation("UtenteModifica");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,139 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace StandManager.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class removedUser : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AspNetUserClaims");
migrationBuilder.DropTable(
name: "AspNetUserLogins");
migrationBuilder.DropTable(
name: "AspNetUserTokens");
migrationBuilder.DropTable(
name: "AspNetUsers");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AspNetUsers",
columns: table => new
{
Id = table.Column<string>(type: "nvarchar(450)", nullable: false),
AccessFailedCount = table.Column<int>(type: "int", nullable: false),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(max)", nullable: true),
Email = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
EmailConfirmed = table.Column<bool>(type: "bit", nullable: false),
LockoutEnabled = table.Column<bool>(type: "bit", nullable: false),
LockoutEnd = table.Column<DateTimeOffset>(type: "datetimeoffset", nullable: true),
NormalizedEmail = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
NormalizedUserName = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
PasswordHash = table.Column<string>(type: "nvarchar(max)", nullable: true),
PhoneNumber = table.Column<string>(type: "nvarchar(max)", nullable: true),
PhoneNumberConfirmed = table.Column<bool>(type: "bit", nullable: false),
SecurityStamp = table.Column<string>(type: "nvarchar(max)", nullable: true),
TwoFactorEnabled = table.Column<bool>(type: "bit", nullable: false),
UserName = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AspNetUserClaims",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
ClaimType = table.Column<string>(type: "nvarchar(max)", nullable: true),
ClaimValue = table.Column<string>(type: "nvarchar(max)", nullable: true),
UserId = table.Column<string>(type: "nvarchar(450)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserLogins",
columns: table => new
{
LoginProvider = table.Column<string>(type: "nvarchar(450)", nullable: false),
ProviderKey = table.Column<string>(type: "nvarchar(450)", nullable: false),
ProviderDisplayName = table.Column<string>(type: "nvarchar(max)", nullable: true),
UserId = table.Column<string>(type: "nvarchar(450)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
table.ForeignKey(
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserTokens",
columns: table => new
{
UserId = table.Column<string>(type: "nvarchar(450)", nullable: false),
LoginProvider = table.Column<string>(type: "nvarchar(450)", nullable: false),
Name = table.Column<string>(type: "nvarchar(450)", nullable: false),
Value = table.Column<string>(type: "nvarchar(max)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
table.ForeignKey(
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_AspNetUserClaims_UserId",
table: "AspNetUserClaims",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserLogins_UserId",
table: "AspNetUserLogins",
column: "UserId");
migrationBuilder.CreateIndex(
name: "EmailIndex",
table: "AspNetUsers",
column: "NormalizedEmail");
migrationBuilder.CreateIndex(
name: "UserNameIndex",
table: "AspNetUsers",
column: "NormalizedUserName",
unique: true,
filter: "[NormalizedUserName] IS NOT NULL");
}
}
}

View File

@ -0,0 +1,92 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using StandManager.Infrastructure.DAL.Context;
#nullable disable
namespace StandManager.Infrastructure.Migrations
{
[DbContext(typeof(StandManagerDbContext))]
partial class StandManagerDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.11")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("StandManager.Domain.Entita.Utente", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<string>("Cognome")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<DateTime>("DataCreazione")
.HasColumnType("datetime2");
b.Property<DateTime?>("DataModifica")
.HasColumnType("datetime2");
b.Property<bool>("Eliminato")
.HasColumnType("bit");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<Guid?>("IdUtenteCreazione")
.HasColumnType("uniqueidentifier");
b.Property<Guid?>("IdUtenteModifica")
.HasColumnType("uniqueidentifier");
b.Property<string>("Nome")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Username")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.HasIndex("IdUtenteCreazione");
b.HasIndex("IdUtenteModifica");
b.ToTable("Utente");
});
modelBuilder.Entity("StandManager.Domain.Entita.Utente", b =>
{
b.HasOne("StandManager.Domain.Entita.Utente", "UtenteCreazione")
.WithMany()
.HasForeignKey("IdUtenteCreazione");
b.HasOne("StandManager.Domain.Entita.Utente", "UtenteModifica")
.WithMany()
.HasForeignKey("IdUtenteModifica");
b.Navigation("UtenteCreazione");
b.Navigation("UtenteModifica");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -8,11 +8,12 @@
<ItemGroup> <ItemGroup>
<SupportedPlatform Include="browser"/> <SupportedPlatform Include="browser" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.21"/> <PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.21" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.22" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.11" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.11"> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.11">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
@ -31,6 +32,9 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Reference Include="OAService.Domain">
<HintPath>..\Libs\OAService.Domain.dll</HintPath>
</Reference>
<Reference Include="OAService.Infrastructure"> <Reference Include="OAService.Infrastructure">
<HintPath>..\Libs\OAService.Infrastructure.dll</HintPath> <HintPath>..\Libs\OAService.Infrastructure.dll</HintPath>
</Reference> </Reference>

View File

@ -1,6 +1,7 @@
namespace StandManager.Service.Interfaces; namespace StandManager.Service.Interfaces
public interface IManagerService
{ {
public interface IManagerService
{
public IUtenteService UtenteService { get; set; } public IUtenteService UtenteService { get; set; }
}
} }

View File

@ -0,0 +1,15 @@
using System.Security.Claims;
namespace StandManager.Service.Interfaces
{
// public interface IMembershipService
// {
// Task<LoginResult> TryLoginAsync(LoginModel model);
// }
// public record LoginResult(bool Success, string? ErrorMessage, ClaimsPrincipal? ClaimsPrincipal)
// {
// public static LoginResult Fail(string msg) => new(false, msg, null);
// public static LoginResult Success(ClaimsPrincipal cp) => new(true, null, cp);
// }
}

View File

@ -1,4 +1,4 @@
using StandManager.Service.Interfaces; using StandManager.Service.Interfaces;
namespace StandManager.Service; namespace StandManager.Service;

View File

@ -1,3 +1,4 @@
using OAService.Infrastructure.DAL.Context;
using OAService.Infrastructure.DAL.Repository; using OAService.Infrastructure.DAL.Repository;
using StandManager.Infrastructure.DAL.Context; using StandManager.Infrastructure.DAL.Context;

View File

@ -1,6 +1,6 @@
<Solution> <Solution>
<Project Path="StandManager.Domain/StandManager.Domain.csproj" Type="C#" /> <Project Path="StandManager.Domain/StandManager.Domain.csproj" />
<Project Path="StandManager.Infrastructure/StandManager.Infrastructure.csproj" Type="C#" /> <Project Path="StandManager.Infrastructure/StandManager.Infrastructure.csproj" />
<Project Path="StandManager.Service/StandManager.Service.csproj" Type="C#" /> <Project Path="StandManager.Service/StandManager.Service.csproj" />
<Project Path="StandManager/StandManager.csproj" /> <Project Path="StandManager/StandManager.csproj" />
</Solution> </Solution>

View File

@ -0,0 +1,59 @@
using Microsoft.AspNetCore.Components;
using System.Diagnostics.CodeAnalysis;
namespace StandManager.Components.Account
{
internal sealed class IdentityRedirectManager(NavigationManager navigationManager)
{
public const string StatusCookieName = "Identity.StatusMessage";
private static readonly CookieBuilder StatusCookieBuilder = new()
{
SameSite = SameSiteMode.Strict,
HttpOnly = true,
IsEssential = true,
MaxAge = TimeSpan.FromSeconds(5),
};
[DoesNotReturn]
public void RedirectTo(string? uri)
{
uri ??= "";
// Prevent open redirects.
if (!Uri.IsWellFormedUriString(uri, UriKind.Relative))
{
uri = navigationManager.ToBaseRelativePath(uri);
}
// During static rendering, NavigateTo throws a NavigationException which is handled by the framework as a redirect.
// So as long as this is called from a statically rendered Identity component, the InvalidOperationException is never thrown.
navigationManager.NavigateTo(uri);
throw new InvalidOperationException($"{nameof(IdentityRedirectManager)} can only be used during static rendering.");
}
[DoesNotReturn]
public void RedirectTo(string uri, Dictionary<string, object?> queryParameters)
{
var uriWithoutQuery = navigationManager.ToAbsoluteUri(uri).GetLeftPart(UriPartial.Path);
var newUri = navigationManager.GetUriWithQueryParameters(uriWithoutQuery, queryParameters);
RedirectTo(newUri);
}
[DoesNotReturn]
public void RedirectToWithStatus(string uri, string message, HttpContext context)
{
context.Response.Cookies.Append(StatusCookieName, message, StatusCookieBuilder.Build(context));
RedirectTo(uri);
}
private string CurrentPath => navigationManager.ToAbsoluteUri(navigationManager.Uri).GetLeftPart(UriPartial.Path);
[DoesNotReturn]
public void RedirectToCurrentPage() => RedirectTo(CurrentPath);
[DoesNotReturn]
public void RedirectToCurrentPageWithStatus(string message, HttpContext context)
=> RedirectToWithStatus(CurrentPath, message, context);
}
}

View File

@ -0,0 +1,46 @@
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Server;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using StandManager.Domain.Entita;
using System.Security.Claims;
namespace StandManager.Components.Account
{
internal sealed class IdentityRevalidatingAuthenticationStateProvider(
ILoggerFactory loggerFactory,
IServiceScopeFactory scopeFactory,
IOptions<IdentityOptions> options)
: RevalidatingServerAuthenticationStateProvider(loggerFactory)
{
protected override TimeSpan RevalidationInterval => TimeSpan.FromMinutes(30);
protected override async Task<bool> ValidateAuthenticationStateAsync(
AuthenticationState authenticationState, CancellationToken cancellationToken)
{
// Get the user manager from a new scope to ensure it fetches fresh data
await using var scope = scopeFactory.CreateAsyncScope();
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
return await ValidateSecurityStampAsync(userManager, authenticationState.User);
}
private async Task<bool> ValidateSecurityStampAsync(UserManager<ApplicationUser> userManager, ClaimsPrincipal principal)
{
var user = await userManager.GetUserAsync(principal);
if (user is null)
{
return false;
}
else if (!userManager.SupportsUserSecurityStamp)
{
return true;
}
else
{
var principalStamp = principal.FindFirstValue(options.Value.ClaimsIdentity.SecurityStampClaimType);
var userStamp = await userManager.GetSecurityStampAsync(user);
return principalStamp == userStamp;
}
}
}
}

View File

@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Identity;
using StandManager.Domain.Entita;
namespace StandManager.Components.Account
{
internal sealed class IdentityUserAccessor(UserManager<ApplicationUser> userManager, IdentityRedirectManager redirectManager)
{
public async Task<ApplicationUser> GetRequiredUserAsync(HttpContext context)
{
var user = await userManager.GetUserAsync(context.User);
if (user is null)
{
redirectManager.RedirectToWithStatus("Account/InvalidUser", $"Error: Unable to load user with ID '{userManager.GetUserId(context.User)}'.", context);
}
return user;
}
}
}

View File

@ -3,9 +3,9 @@
<head> <head>
<base href="/" /> <base href="/" />
<meta charset="utf-8"/> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"/> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta http-equiv="X-UA-Compatible" content="ie=edge"/> <meta http-equiv="X-UA-Compatible" content="ie=edge" />
<link href="/lib/tabler/tabler.min.css" rel="stylesheet" /> <link href="/lib/tabler/tabler.min.css" rel="stylesheet" />
<link href="/css/tabler-flags.css" rel="stylesheet" /> <link href="/css/tabler-flags.css" rel="stylesheet" />
<link href="/css/tabler-socials.css" rel="stylesheet" /> <link href="/css/tabler-socials.css" rel="stylesheet" />
@ -17,11 +17,13 @@
<link href="/libs/Fontawesome/css/all.min.css" rel="stylesheet" /> <link href="/libs/Fontawesome/css/all.min.css" rel="stylesheet" />
<link href="/libs/Fontawesome/css/regular.min.css" rel="stylesheet" /> <link href="/libs/Fontawesome/css/regular.min.css" rel="stylesheet" />
<link rel="icon" type="image/png" href="favicon.png" /> <link rel="icon" type="image/png" href="favicon.png" />
<HeadOutlet/> <HeadOutlet />
</head> </head>
<body> <body>
<Routes/> <div class="page">
<Routes />
</div>
<script src="_framework/blazor.web.js"></script> <script src="_framework/blazor.web.js"></script>

View File

@ -1,10 +1,7 @@
@using Microsoft.AspNetCore.Authentication @using Microsoft.AspNetCore.Authentication
@inherits LayoutComponentBase @inherits LayoutComponentBase
<div class="page">
<body class="body-marketing body-gradient">
<div class="page">
<!-- NAV MENU MANAGEMENT --> <!-- NAV MENU MANAGEMENT -->
<header class="navbar navbar-expand-md d-print-none" > <header class="navbar navbar-expand-md d-print-none" >
<div class="container-xl"> <div class="container-xl">
@ -29,8 +26,7 @@
<div class="dropdown-menu dropdown-menu-end dropdown-menu-arrow"> <div class="dropdown-menu dropdown-menu-end dropdown-menu-arrow">
<a href="/management/profile" class="dropdown-item">Il mio profilo</a> <a href="/management/profile" class="dropdown-item">Il mio profilo</a>
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<button class="dropdown-item" @onclick="OnLogoutPressed">Settings</button> <a href="/account/logout" class="dropdown-item"> Logout </a>
<a @onclick="OnLogoutPressed" class="dropdown-item">Logout @context.User.Identity?.Name 1</a>
</div> </div>
</div> </div>
</div> </div>
@ -47,13 +43,21 @@
<!-- BEGIN NAVBAR MENU --> <!-- BEGIN NAVBAR MENU -->
<ul class="navbar-nav"> <ul class="navbar-nav">
<li class="nav-item active"> <li class="nav-item active">
<a class="nav-link" href="/management"> <a class="nav-link" href="/">
<span class="nav-link-icon d-md-none d-lg-inline-block"> <span class="nav-link-icon d-md-none d-lg-inline-block">
<i class="fa-solid fa-house"></i> <i class="fa-solid fa-house"></i>
</span> </span>
<span class="nav-link-title"> Home </span> <span class="nav-link-title"> Home </span>
</a> </a>
</li> </li>
<li class="nav-item">
<a class="nav-link" href="/management/dashboard">
<span class="nav-link-icon d-md-none d-lg-inline-block">
<i class="fa-solid fa-house"></i>
</span>
<span class="nav-link-title"> Dashboard </span>
</a>
</li>
</ul> </ul>
</div> </div>
</div> </div>
@ -61,16 +65,15 @@
</div> </div>
</div> </div>
</header> </header>
</div> </div>
@Body
</body>
@Body
@code { @code {
[CascadingParameter] public HttpContext httpContext { get; set; } = default; [CascadingParameter] public HttpContext httpContext { get; set; } = default;
private async Task OnLogoutPressed(MouseEventArgs e) private async Task OnLogoutPressed(MouseEventArgs e)
{ {
var a = "Ciao";
@* await httpContext.SignOutAsync(); *@ @* await httpContext.SignOutAsync(); *@
} }
} }

View File

@ -0,0 +1,90 @@
@layout PublicLayout
@page "/account/login"
@using Microsoft.AspNetCore.Authentication
@using Microsoft.AspNetCore.Authentication.Cookies
@using Microsoft.AspNetCore.Identity
@using StandManager.Components.Layout
@using StandManager.Domain.Entita
@using StandManager.Infrastructure.DAL.Context
@using StandManager.Model
@using System.Security.Claims
@using StandManager.Service.Interfaces
@inject StandManagerDbContext dbContext
@inject NavigationManager navi
@inject IHttpContextAccessor HttpContextAccessor
@inject IManagerService _managerService
<div class="page page-center">
<div class="container container-tight py-4">
<div class="text-center mb-4">
</div>
<div class="card card-md">
<div class="card-body">
<h2 class="h2 text-center mb-4">Accedi</h2>
<EditForm Model="model" OnValidSubmit="HandleValidSubmit" FormName="loginForm">
<DataAnnotationsValidator />
<div class="mb-3">
<label class="form-label">Email</label>
<InputText class="form-control" @bind-Value="model!.Email" />
<ValidationMessage For="@(() => model!.Email)" />
</div>
<div class="mb-3">
<label class="form-label">Password</label>
<InputText class="form-control" @bind-Value="model!.Password" type="password" />
<ValidationMessage For="@(() => model!.Password)" />
</div>
<button type="submit" class="btn btn-primary w-100">
Accedi
</button>
@if (!string.IsNullOrEmpty(errorMessage))
{
<div class="alert alert-danger mt-3">@errorMessage</div>
}
</EditForm>
</div>
</div>
</div>
</div>
@code {
[SupplyParameterFromForm]
private LoginModel? model { get; set; }
private string? errorMessage { get; set; }
[CascadingParameter]
public HttpContext? httpContext { get; set; }
protected override void OnInitialized() => model ??= new();
private async Task HandleValidSubmit(EditContext args)
{
var user = await _managerService.UtenteService.RicercaPer(x => x.Email == model.Email);
var hasher = new PasswordHasher<Utente>();
if (user == null ||
hasher.VerifyHashedPassword(user, user.Password, model.Password) != PasswordVerificationResult.Success)
{
// credenziali non valide
errorMessage = "Credenziali non valide.";
return;
}
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, user.Email),
new Claim(ClaimTypes.Role, "Admin")
};
var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
var principal = new ClaimsPrincipal(identity);
await httpContext.SignInAsync(principal);
navi.NavigateTo("/management/dashboard");
}
}

View File

@ -0,0 +1,15 @@
@page "/account/logout"
@using Microsoft.AspNetCore.Authentication
@inject NavigationManager navManager
@code {
[CascadingParameter]
public HttpContext? httpContext { get; set; }
protected override async Task OnInitializedAsync()
{
await httpContext.SignOutAsync();
navManager.NavigateTo("/");
}
}

View File

@ -1,4 +1,7 @@
@page "/" @page "/"
@rendermode InteractiveServer
@using Microsoft.AspNetCore.Identity
@using StandManager.Domain.Entita
<PageTitle>Home</PageTitle> <PageTitle>Home</PageTitle>

View File

@ -1,4 +1,5 @@
@page "/management" @page "/management/Dashboard"
@using Microsoft.AspNetCore.Authorization @using Microsoft.AspNetCore.Authorization
@using StandManager.Components.Layout @using StandManager.Components.Layout
@attribute [Authorize] @attribute [Authorize]
@ -10,7 +11,9 @@
<div class="container-xl"> <div class="container-xl">
<div class="row g-2 align-items-center"> <div class="row g-2 align-items-center">
<div class="col"> <div class="col">
<h2 class="page-title">Home</h2> <!-- Page pre-title -->
<div class="page-pretitle">Overview</div>
<h2 class="page-title">Dashboard</h2>
</div> </div>
</div> </div>
</div> </div>
@ -18,5 +21,9 @@
</div> </div>
@code { @code {
override protected void OnInitialized()
{
// Initialization logic can be added here if needed
var a = "CIAO";
}
} }

View File

@ -4,12 +4,18 @@
@using System.Security.Claims @using System.Security.Claims
@using Microsoft.AspNetCore.Authentication @using Microsoft.AspNetCore.Authentication
@using Microsoft.AspNetCore.Identity @using Microsoft.AspNetCore.Identity
@using OAService.Domain.Entita
@using StandManager.Components.Layout @using StandManager.Components.Layout
@using StandManager.Domain.Entita @using StandManager.Domain.Entita
@using StandManager.Model @using StandManager.Model
@using StandManager.Service.Interfaces @using StandManager.Service.Interfaces
@inject NavigationManager Nav @using Microsoft.AspNetCore.Http
@inject IManagerService _managerService @inject NavigationManager Navigation
@inject IHttpContextAccessor HttpContextAccessor
@inject HttpClient Http
@inject UserManager<ApplicationUser> UserManager
@inject IUserStore<ApplicationUser> UserStore
@inject SignInManager<ApplicationUser> SignInManager
<div class="page page-center"> <div class="page page-center">
<div class="container container-tight py-4"> <div class="container container-tight py-4">
@ -23,14 +29,14 @@
<div class="mb-3"> <div class="mb-3">
<label class="form-label">Email</label> <label class="form-label">Email</label>
<InputText class="form-control" @bind-Value="model.Email"/> <InputText class="form-control" @bind-Value="model!.Email"/>
<ValidationMessage For="@(() => model.Email)"/> <ValidationMessage For="@(() => model!.Email)"/>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label class="form-label">Password</label> <label class="form-label">Password</label>
<InputText class="form-control" @bind-Value="model.Password" type="password"/> <InputText class="form-control" @bind-Value="model!.Password" type="password"/>
<ValidationMessage For="@(() => model.Password)"/> <ValidationMessage For="@(() => model!.Password)"/>
</div> </div>
<button type="submit" class="btn btn-primary w-100"> <button type="submit" class="btn btn-primary w-100">
@ -48,38 +54,36 @@
</div> </div>
@code { @code {
[CascadingParameter] public HttpContext httpContext { get; set; } = default;
[SupplyParameterFromForm] [SupplyParameterFromForm]
private LoginModel model { get; set; } private LoginModel? model { get; set; }
private string? errorMessage; private string? errorMessage;
protected override void OnInitialized() => model ??= new(); protected override void OnInitialized() => model ??= new();
private async Task HandleValidSubmit() private async Task HandleValidSubmit()
{ {
errorMessage = null; var u = UserManager.Users.FirstOrDefault();
var result = await SignInManager.CheckPasswordSignInAsync(u, "test123pwd@", lockoutOnFailure: false);
var user = await _managerService.UtenteService.RicercaPer(x => x.Email == model.Email); if (result.Succeeded)
var hasher = new PasswordHasher<Utente>();
if (user == null || hasher.VerifyHashedPassword(user, user.Password, model.Password) != PasswordVerificationResult.Success)
{ {
errorMessage = "Credenziali non valide."; await SignInManager.SignInAsync(u, isPersistent: true, "standmanager");
return;
} }
Navigation.NavigateTo("management/Dashboard");
// var response = await Http.PostAsJsonAsync("/management/adminLogin", model);
List<Claim> claims = // if (!response.IsSuccessStatusCode)
[ // {
new(ClaimTypes.Name, user.Email), // // leggiamo il messaggio dall'endpoint (opzionale)
new(ClaimTypes.GivenName, user.Nome), // var msg = await response.Content.ReadAsStringAsync();
new("Id", user.Id.ToString()) // errorMessage = string.IsNullOrWhiteSpace(msg)
]; // ? "Credenziali non valide."
ClaimsIdentity identity = new(claims, "standmanager"); // : msg;
ClaimsPrincipal claimsPrincipal = new(identity);
await httpContext.SignInAsync("standmanager", claimsPrincipal, new AuthenticationProperties // return;
{ // }
IsPersistent = true, // var u = await _managerService.UtenteService.RicercaPer(x => x.Email == model!.Email);
ExpiresUtc = DateTime.UtcNow.AddHours(8) // await SignInManager.SignInAsync(new ApplicationUser(), new AuthenticationProperties { IsPersistent = false });
}); // // Login ok → vai al management
Nav.NavigateTo("/management"); // Navigation.NavigateTo("management/Dashboard");
} }
} }

View File

@ -0,0 +1,40 @@
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using StandManager.Domain.Entita;
using StandManager.Model;
using StandManager.Service.Interfaces;
public static class LoginUtils
{
public static async Task<IResult> OnLogin(LoginModel model, IManagerService managerService, HttpContext ctx)
{
var user = await managerService.UtenteService.RicercaPer(x => x.Email == model.Email);
var hasher = new PasswordHasher<Utente>();
if (user == null ||
hasher.VerifyHashedPassword(user, user.Password, model.Password) != PasswordVerificationResult.Success)
{
// credenziali non valide
return Results.BadRequest("Credenziali non valide.");
}
List<Claim> claims =
[
new(ClaimTypes.Name, user.Email),
new(ClaimTypes.GivenName, user.Nome),
new("Id", user.Id.ToString())
];
ClaimsIdentity identity = new(claims, "standmanager");
ClaimsPrincipal claimsPrincipal = new(identity);
await ctx.SignInAsync("standmanager", claimsPrincipal, new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTime.UtcNow.AddHours(8)
});
return Results.Ok();
}
}

View File

@ -1,13 +1,20 @@
using System.Reflection; using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Radzen; using Radzen;
using StandManager.Components; using StandManager.Components;
using StandManager.Components.Account;
using StandManager.Domain.Entita;
using StandManager.Infrastructure.DAL.Context; using StandManager.Infrastructure.DAL.Context;
using StandManager.Model;
using StandManager.Service; using StandManager.Service;
using StandManager.Service.Interfaces; using StandManager.Service.Interfaces;
using StandManager.Service.Repository; using StandManager.Service.Repository;
using StandManager.Utils; using StandManager.Utils;
using System.Reflection;
using System.Security.Claims;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
@ -16,12 +23,19 @@ builder.Services.AddRazorComponents()
.AddInteractiveServerComponents(); .AddInteractiveServerComponents();
builder.Services.AddCascadingAuthenticationState(); builder.Services.AddCascadingAuthenticationState();
//builder.Services.AddScoped<IdentityUserAccessor>();
//builder.Services.AddScoped<IdentityRedirectManager>();
//builder.Services.AddScoped<AuthenticationStateProvider, IdentityRevalidatingAuthenticationStateProvider>();
//Database builder.Services.Configure<IdentityOptions>(options =>
var connectionString = builder.Configuration.GetConnectionString("ConnectionString"); {
builder.Services.AddDbContext<StandManagerDbContext>(options => options.Password.RequireDigit = false;
options.UseSqlServer(connectionString) options.Password.RequireLowercase = false;
); options.Password.RequireUppercase = false;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequiredLength = 1; // puoi metterla anche a 1
options.Password.RequiredUniqueChars = 0;
});
//DI //DI
var types = Assembly.Load("StandManager.Service").GetTypes(); var types = Assembly.Load("StandManager.Service").GetTypes();
@ -31,32 +45,36 @@ foreach (var intfc in allProviderTypes.Where(t => t.IsInterface))
var impl = allProviderTypes.FirstOrDefault(c => c.IsClass && intfc.Name[1..] == c.Name); var impl = allProviderTypes.FirstOrDefault(c => c.IsClass && intfc.Name[1..] == c.Name);
if (impl != null) builder.Services.AddScoped(intfc, impl); if (impl != null) builder.Services.AddScoped(intfc, impl);
} }
//Database
var connectionString = builder.Configuration.GetConnectionString("ConnectionString");
builder.Services.AddDbContext<StandManagerDbContext>(options =>
options.UseSqlServer(connectionString)
);
builder.Services.AddScoped(typeof(IStandManagerGenericRepository<>), typeof(StandManagerGenericRepository<>)); builder.Services.AddScoped(typeof(IStandManagerGenericRepository<>), typeof(StandManagerGenericRepository<>));
builder.Services.AddScoped<IStandManagerUnitOfWork, StandManagerUnitOfWork>(); builder.Services.AddScoped<IStandManagerUnitOfWork, StandManagerUnitOfWork>();
builder.Services.AddScoped<IManagerService, ManagerService>(); builder.Services.AddScoped<IManagerService, ManagerService>();
builder.Services.AddScoped<LayoutState>(); builder.Services.AddScoped<LayoutState>();
builder.Services.AddRadzenComponents(); builder.Services.AddRadzenComponents();
builder.Services
.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = "standmanager";
options.DefaultSignInScheme = "standmanager";
options.DefaultChallengeScheme = "standmanager";
})
.AddCookie("standmanager", options =>
{
options.LoginPath = "/management/login";
options.AccessDeniedPath = "/management/access-denied";
options.ExpireTimeSpan = TimeSpan.FromHours(8);
options.SlidingExpiration = true;
});
builder.Services.AddAuthorization();
builder.Services.AddHttpContextAccessor(); builder.Services.AddHttpContextAccessor();
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.Cookie.Name = "auth_token";
options.Cookie.MaxAge = TimeSpan.FromMinutes(30);
options.LoginPath = "/account/login";
options.AccessDeniedPath = "/access-denied";
});
builder.Services.AddAuthorization();
builder.Services.AddCascadingAuthenticationState();
builder.Services.AddDbContext<StandManagerDbContext>(options =>
{
options.UseSqlServer(connectionString);
});
var app = builder.Build(); var app = builder.Build();
// Configure the HTTP request pipeline. // Configure the HTTP request pipeline.
@ -72,11 +90,34 @@ else
} }
app.UseHttpsRedirection(); app.UseHttpsRedirection();
app.UseStaticFiles(); app.UseStaticFiles();
app.UseAntiforgery(); app.UseAntiforgery();
app.UseAuthentication();
app.UseAuthorization();
app.MapRazorComponents<App>() app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode(); .AddInteractiveServerRenderMode();
app.Use(async (context, func) =>
{
try
{
await func();
}
catch (Exception e)
{
var logger = context.RequestServices.GetService<ILogger<Program>>();
// Log dell'eccezione
logger?.LogError(e, "Si è verificata un'eccezione durante l'elaborazione della richiesta.");
context.Response.Clear();
context.Response.StatusCode = e is BadHttpRequestException badHttpRequestException
? badHttpRequestException.StatusCode
: 500;
}
});
await app.RunAsync(); await app.RunAsync();

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
@ -8,6 +8,8 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="8.0.22" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.22" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.11"> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.11">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

View File

@ -1,6 +1,6 @@
{ {
"ConnectionStrings": { "ConnectionStrings": {
"ConnectionString": "Data Source=192.168.0.233\\SQL2019;Initial Catalog=DAC_Eventi;Persist Security Info=True;User ID=dac_user;Password=KZ4ZrUPzJV;TrustServerCertificate=True" "ConnectionString": "Data Source=192.168.0.233\\SQL2019;Initial Catalog=DAC_StandManager;Persist Security Info=True;User ID=dac_user;Password=KZ4ZrUPzJV;TrustServerCertificate=True"
}, },
"Logging": { "Logging": {
"LogLevel": { "LogLevel": {