From 0c4d13caed53b2702eef41461d0c8a4b25df48f6 Mon Sep 17 00:00:00 2001 From: Sergey Chebotar Date: Mon, 6 Mar 2023 07:41:35 +0300 Subject: [PATCH] Base authorization/authentification --- .dockerignore | 4 +- .gitignore | 8 +- Controllers/AccountController.cs | 80 ++++++ Controllers/BundleController.cs | 2 + Controllers/FigureController.cs | 2 + ...ner.cs => 20230303041621_Init.Designer.cs} | 2 +- ...1044417_Init.cs => 20230303041621_Init.cs} | 0 .../Identity/20230303041342_Init.Designer.cs | 268 ++++++++++++++++++ Migrations/Identity/20230303041342_Init.cs | 222 +++++++++++++++ .../Identity/IdentityContextModelSnapshot.cs | 265 +++++++++++++++++ Models/IdentityContext.cs | 13 + Models/LoginModel.cs | 13 + Models/SeedData.cs | 64 ----- MyDarling.csproj | 1 + Program.cs | 13 +- Views/Account/Create.cshtml | 35 +++ Views/Account/List.cshtml | 54 ++++ Views/Account/Login.cshtml | 31 ++ Views/Bundle/Index.cshtml | 10 + appsettings.json | 3 +- 20 files changed, 1014 insertions(+), 76 deletions(-) create mode 100644 Controllers/AccountController.cs rename Migrations/{20230221044417_Init.Designer.cs => 20230303041621_Init.Designer.cs} (98%) rename Migrations/{20230221044417_Init.cs => 20230303041621_Init.cs} (100%) create mode 100644 Migrations/Identity/20230303041342_Init.Designer.cs create mode 100644 Migrations/Identity/20230303041342_Init.cs create mode 100644 Migrations/Identity/IdentityContextModelSnapshot.cs create mode 100644 Models/IdentityContext.cs create mode 100644 Models/LoginModel.cs delete mode 100644 Models/SeedData.cs create mode 100644 Views/Account/Create.cshtml create mode 100644 Views/Account/List.cshtml create mode 100644 Views/Account/Login.cshtml diff --git a/.dockerignore b/.dockerignore index f11c5d6..858d1b3 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,4 +1,2 @@ # database file -Database/MyDarlingDb.db -Database/MyDarlingDb.db-shm -Database/MyDarlingDb.db-wal \ No newline at end of file +Database/* \ No newline at end of file diff --git a/.gitignore b/.gitignore index 576bf4d..e767ca3 100644 --- a/.gitignore +++ b/.gitignore @@ -456,10 +456,8 @@ $RECYCLE.BIN/ # libman libraries wwwroot/lib/* -# database image content +# image content wwwroot/content/* -# database file -Database/MyDarlingDb.db -Database/MyDarlingDb.db-shm -Database/MyDarlingDb.db-wal \ No newline at end of file +# database files +Database/* \ No newline at end of file diff --git a/Controllers/AccountController.cs b/Controllers/AccountController.cs new file mode 100644 index 0000000..432b671 --- /dev/null +++ b/Controllers/AccountController.cs @@ -0,0 +1,80 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using MyDarling.Models; + +namespace MyDarling.Controllers; + +public class AccountController : Controller +{ + public UserManager UserManager { get; set; } + private SignInManager SignInManager; + + public AccountController(UserManager userManager, SignInManager signInManager) + { + UserManager = userManager; + SignInManager = signInManager; + } + + public IActionResult List() + { + return View(UserManager.Users); + } + + public IActionResult Create() + { + return View(new IdentityUser()); + } + + [HttpPost] + public async Task Create([Bind] IdentityUser user, [Bind] string Password) + { + if (ModelState.IsValid) + { + IdentityResult result = await UserManager.CreateAsync(user, Password); + if (result.Succeeded) + { + return RedirectToAction(nameof(List)); + } + + foreach (IdentityError error in result.Errors) + { + ModelState.AddModelError("", error.Description); + } + } + return View(); + } + + public ViewResult Login(string returlUrl) + { + return View(new LoginModel { ReturnUrl = returlUrl }); + } + + [HttpPost] + public async Task Login(LoginModel loginModel) + { + if (ModelState.IsValid) + { + IdentityUser user = await UserManager.FindByNameAsync(loginModel.Name); + if (user != null) + { + await SignInManager.SignOutAsync(); + if ((await SignInManager.PasswordSignInAsync(user, + loginModel.Password, false, false)) + .Succeeded) + { + return Redirect(loginModel?.ReturnUrl ?? "/Bundle"); + } + } + ModelState.AddModelError("", "Invalid name or password"); + } + return View(loginModel); + } + + [Authorize] + public async Task Logout(string returlUrl = "/Account/Login") + { + await SignInManager.SignOutAsync(); + return Redirect(returlUrl); + } +} \ No newline at end of file diff --git a/Controllers/BundleController.cs b/Controllers/BundleController.cs index 9e5c2d9..b1d61fd 100644 --- a/Controllers/BundleController.cs +++ b/Controllers/BundleController.cs @@ -1,10 +1,12 @@ using System.Data; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using MyDarling.Models; namespace MyDarling.Controllers { + [Authorize] public class BundleController : Controller { private DataContext context; diff --git a/Controllers/FigureController.cs b/Controllers/FigureController.cs index 3329968..9f6cf0c 100644 --- a/Controllers/FigureController.cs +++ b/Controllers/FigureController.cs @@ -1,10 +1,12 @@ using System.Data; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using MyDarling.Models; namespace MyDarling.Controllers { + [Authorize] public class FigureController : Controller { private DataContext context; diff --git a/Migrations/20230221044417_Init.Designer.cs b/Migrations/20230303041621_Init.Designer.cs similarity index 98% rename from Migrations/20230221044417_Init.Designer.cs rename to Migrations/20230303041621_Init.Designer.cs index 658e6b7..833e097 100644 --- a/Migrations/20230221044417_Init.Designer.cs +++ b/Migrations/20230303041621_Init.Designer.cs @@ -11,7 +11,7 @@ using MyDarling.Models; namespace MyDarling.Migrations { [DbContext(typeof(DataContext))] - [Migration("20230221044417_Init")] + [Migration("20230303041621_Init")] partial class Init { /// diff --git a/Migrations/20230221044417_Init.cs b/Migrations/20230303041621_Init.cs similarity index 100% rename from Migrations/20230221044417_Init.cs rename to Migrations/20230303041621_Init.cs diff --git a/Migrations/Identity/20230303041342_Init.Designer.cs b/Migrations/Identity/20230303041342_Init.Designer.cs new file mode 100644 index 0000000..bdac6bd --- /dev/null +++ b/Migrations/Identity/20230303041342_Init.Designer.cs @@ -0,0 +1,268 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using MyDarling.Models; + +#nullable disable + +namespace MyDarling.Migrations.Identity +{ + [DbContext(typeof(IdentityContext))] + [Migration("20230303041342_Init")] + partial class Init + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "7.0.2"); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Migrations/Identity/20230303041342_Init.cs b/Migrations/Identity/20230303041342_Init.cs new file mode 100644 index 0000000..fd7f4e6 --- /dev/null +++ b/Migrations/Identity/20230303041342_Init.cs @@ -0,0 +1,222 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MyDarling.Migrations.Identity +{ + /// + public partial class Init : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AspNetRoles", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + Name = table.Column(type: "TEXT", maxLength: 256, nullable: true), + NormalizedName = table.Column(type: "TEXT", maxLength: 256, nullable: true), + ConcurrencyStamp = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetRoles", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AspNetUsers", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + UserName = table.Column(type: "TEXT", maxLength: 256, nullable: true), + NormalizedUserName = table.Column(type: "TEXT", maxLength: 256, nullable: true), + Email = table.Column(type: "TEXT", maxLength: 256, nullable: true), + NormalizedEmail = table.Column(type: "TEXT", maxLength: 256, nullable: true), + EmailConfirmed = table.Column(type: "INTEGER", nullable: false), + PasswordHash = table.Column(type: "TEXT", nullable: true), + SecurityStamp = table.Column(type: "TEXT", nullable: true), + ConcurrencyStamp = table.Column(type: "TEXT", nullable: true), + PhoneNumber = table.Column(type: "TEXT", nullable: true), + PhoneNumberConfirmed = table.Column(type: "INTEGER", nullable: false), + TwoFactorEnabled = table.Column(type: "INTEGER", nullable: false), + LockoutEnd = table.Column(type: "TEXT", nullable: true), + LockoutEnabled = table.Column(type: "INTEGER", nullable: false), + AccessFailedCount = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUsers", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AspNetRoleClaims", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + RoleId = table.Column(type: "TEXT", nullable: false), + ClaimType = table.Column(type: "TEXT", nullable: true), + ClaimValue = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id); + table.ForeignKey( + name: "FK_AspNetRoleClaims_AspNetRoles_RoleId", + column: x => x.RoleId, + principalTable: "AspNetRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserClaims", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + UserId = table.Column(type: "TEXT", nullable: false), + ClaimType = table.Column(type: "TEXT", nullable: true), + ClaimValue = table.Column(type: "TEXT", 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(type: "TEXT", nullable: false), + ProviderKey = table.Column(type: "TEXT", nullable: false), + ProviderDisplayName = table.Column(type: "TEXT", nullable: true), + UserId = table.Column(type: "TEXT", 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: "AspNetUserRoles", + columns: table => new + { + UserId = table.Column(type: "TEXT", nullable: false), + RoleId = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId }); + table.ForeignKey( + name: "FK_AspNetUserRoles_AspNetRoles_RoleId", + column: x => x.RoleId, + principalTable: "AspNetRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AspNetUserRoles_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserTokens", + columns: table => new + { + UserId = table.Column(type: "TEXT", nullable: false), + LoginProvider = table.Column(type: "TEXT", nullable: false), + Name = table.Column(type: "TEXT", nullable: false), + Value = table.Column(type: "TEXT", 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_AspNetRoleClaims_RoleId", + table: "AspNetRoleClaims", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "RoleNameIndex", + table: "AspNetRoles", + column: "NormalizedName", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserClaims_UserId", + table: "AspNetUserClaims", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserLogins_UserId", + table: "AspNetUserLogins", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserRoles_RoleId", + table: "AspNetUserRoles", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "EmailIndex", + table: "AspNetUsers", + column: "NormalizedEmail"); + + migrationBuilder.CreateIndex( + name: "UserNameIndex", + table: "AspNetUsers", + column: "NormalizedUserName", + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AspNetRoleClaims"); + + migrationBuilder.DropTable( + name: "AspNetUserClaims"); + + migrationBuilder.DropTable( + name: "AspNetUserLogins"); + + migrationBuilder.DropTable( + name: "AspNetUserRoles"); + + migrationBuilder.DropTable( + name: "AspNetUserTokens"); + + migrationBuilder.DropTable( + name: "AspNetRoles"); + + migrationBuilder.DropTable( + name: "AspNetUsers"); + } + } +} diff --git a/Migrations/Identity/IdentityContextModelSnapshot.cs b/Migrations/Identity/IdentityContextModelSnapshot.cs new file mode 100644 index 0000000..bb1e61f --- /dev/null +++ b/Migrations/Identity/IdentityContextModelSnapshot.cs @@ -0,0 +1,265 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using MyDarling.Models; + +#nullable disable + +namespace MyDarling.Migrations.Identity +{ + [DbContext(typeof(IdentityContext))] + partial class IdentityContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "7.0.2"); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Models/IdentityContext.cs b/Models/IdentityContext.cs new file mode 100644 index 0000000..888bc7a --- /dev/null +++ b/Models/IdentityContext.cs @@ -0,0 +1,13 @@ +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Identity.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; + +namespace MyDarling.Models; + +public class IdentityContext : IdentityDbContext +{ + public IdentityContext(DbContextOptions options) : base(options) + { + + } +} \ No newline at end of file diff --git a/Models/LoginModel.cs b/Models/LoginModel.cs new file mode 100644 index 0000000..93485c8 --- /dev/null +++ b/Models/LoginModel.cs @@ -0,0 +1,13 @@ +using System.ComponentModel.DataAnnotations; + +namespace MyDarling.Models; +public class LoginModel +{ + [Required] + public string? Name { get; set; } + + [Required] + public string? Password { get; set; } + + public string ReturnUrl { get; set; } = "/Bundle"; +} \ No newline at end of file diff --git a/Models/SeedData.cs b/Models/SeedData.cs deleted file mode 100644 index 3a15543..0000000 --- a/Models/SeedData.cs +++ /dev/null @@ -1,64 +0,0 @@ -// using Microsoft.EntityFrameworkCore; -// namespace MyDarling.Models -// { -// public static class SeedData -// { -// public static void SeedDatabase(DataContext context) -// { -// context.Database.Migrate(); -// if (context.UnderwearBundles.Count() == 0) -// { -// var aliceFigures = new List
-// { -// new Figure() -// { -// Description = @"Комплект из бежевого эластичного кружева с голубой отделкой.", -// FilePath = "/content/0/img/IMG_4896.JPG" -// }, -// new Figure() -// { -// Description = @"В комплект входит бра, 2 трусиков (на высокой посадке и стандартной на регуляции) и чокер. Низ можно сделать на выбор стринги/бразильянки.", -// FilePath = "/content/0/img/IMG_4902.JPG" -// } -// }; - -// var nikkiFigures = new List
-// { -// new Figure() -// { -// Description = @"Базовый сет из мягкой эластичной сетки.", -// FilePath = "/content/1/img/IMG_4897.JPG" -// }, -// new Figure() -// { -// Description = @"В комплект входит лиф на косточках и 2 трусиков – бразильянки на высокой посадке и стринги на стандартной посадке с регуляцией. Доступен в цветах: желтый, черный, бежевый молочный.", -// FilePath = "/content/1/img/IMG_4898.JPG" -// } -// }; - -// context.Figures.AddRange(aliceFigures); -// context.Figures.AddRange(nikkiFigures); -// context.SaveChanges(); - -// var alice = new UnderwearBundle -// { -// Name = "Alice", -// Figures = aliceFigures, -// Description = @"Комплект из бежевого эластичного кружева с голубой отделкой.", -// Price = 3000 -// }; - -// var nikki = new UnderwearBundle -// { -// Name = "Nikki", -// Figures = nikkiFigures, -// Description = @"Базовый сет из мягкой эластичной сетки.", -// Price = 3800 -// }; - -// context.UnderwearBundles.AddRange(alice, nikki); -// context.SaveChanges(); -// } -// } -// } -// } \ No newline at end of file diff --git a/MyDarling.csproj b/MyDarling.csproj index f2e24bf..7ed30cd 100644 --- a/MyDarling.csproj +++ b/MyDarling.csproj @@ -7,6 +7,7 @@ + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/Program.cs b/Program.cs index 61ee7fb..eda78fa 100644 --- a/Program.cs +++ b/Program.cs @@ -1,5 +1,6 @@ using Microsoft.EntityFrameworkCore; using MyDarling.Models; +using Microsoft.AspNetCore.Identity; var builder = WebApplication.CreateBuilder(args); @@ -9,6 +10,14 @@ builder.Services.AddDbContext(opts => opts.EnableSensitiveDataLogging(true); }); +builder.Services.AddDbContext(opts => +{ + opts.UseSqlite(builder.Configuration["ConnectionStrings:IdentityDb"]); +}); + +builder.Services.AddIdentity() + .AddEntityFrameworkStores(); + builder.Services.AddControllersWithViews(); var app = builder.Build(); @@ -17,7 +26,7 @@ app.UseStaticFiles(); app.MapControllers(); app.MapDefaultControllerRoute(); -// var context = app.Services.CreateScope().ServiceProvider.GetRequiredService(); -// SeedData.SeedDatabase(context); +app.UseAuthentication(); +app.UseAuthorization(); app.Run(); \ No newline at end of file diff --git a/Views/Account/Create.cshtml b/Views/Account/Create.cshtml new file mode 100644 index 0000000..2fff64a --- /dev/null +++ b/Views/Account/Create.cshtml @@ -0,0 +1,35 @@ +@using Microsoft.AspNetCore.Identity +@model IdentityUser + + + + + + User Acccounts + + + + +
Create User
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + Back +
+
+ + + \ No newline at end of file diff --git a/Views/Account/List.cshtml b/Views/Account/List.cshtml new file mode 100644 index 0000000..7f17543 --- /dev/null +++ b/Views/Account/List.cshtml @@ -0,0 +1,54 @@ +@using Microsoft.AspNetCore.Identity +@model IQueryable + + + + + + Users + + + + +
+
User Administration
+ + + + + + + + @if (Model.Count() == 0) + { + + + + } + else + { + foreach (IdentityUser user in Model) + { + + + + + + + } + } +
IDNameEmail
No User Accounts
@user.Id@user.UserName@user.Email +
+ + Edit + +
+
+ Create +
+ + + \ No newline at end of file diff --git a/Views/Account/Login.cshtml b/Views/Account/Login.cshtml new file mode 100644 index 0000000..893155c --- /dev/null +++ b/Views/Account/Login.cshtml @@ -0,0 +1,31 @@ +@model MyDarling.Models.LoginModel + + + + + + Login Page + + + + +
+
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ + + \ No newline at end of file diff --git a/Views/Bundle/Index.cshtml b/Views/Bundle/Index.cshtml index 678caf0..9e1f293 100644 --- a/Views/Bundle/Index.cshtml +++ b/Views/Bundle/Index.cshtml @@ -10,6 +10,16 @@ +
+
+
+ Underwear bundle list +
+
+ Log Out +
+
+
diff --git a/appsettings.json b/appsettings.json index 6f63f2f..fc9c46a 100644 --- a/appsettings.json +++ b/appsettings.json @@ -7,6 +7,7 @@ }, "AllowedHosts": "*", "ConnectionStrings": { - "MyDarlingDb": "Data Source=Database/MyDarlingDb.db" + "MyDarlingDb": "Data Source=Database/MyDarlingDb.db", + "IdentityDb": "Data Source=Database/IdentityDb.db" } }