From 82d270a66b8ffca28e321f29b2eb90b2412ac9a7 Mon Sep 17 00:00:00 2001
From: Syndamia
Date: Sat, 8 May 2021 18:10:08 +0300
Subject: Implemented authorization; Replaced Role with IdentityRole;
Renamed UserController to AccountController, updated links
---
ExamTemplate/Common/RoleConst.cs | 8 ++
ExamTemplate/Data/Models/Role.cs | 16 ---
ExamTemplate/Data/Models/User.cs | 1 -
ExamTemplate/Data/TemplateContext.cs | 7 +-
ExamTemplate/Services/UserService.cs | 15 +--
ExamTemplate/Web/Controllers/AccountController.cs | 140 ++++++++++++++++++++++
ExamTemplate/Web/Controllers/UserController.cs | 131 --------------------
ExamTemplate/Web/Startup.cs | 31 +++--
ExamTemplate/Web/Views/Account/Edit.cshtml | 20 ++++
ExamTemplate/Web/Views/Account/Login.cshtml | 14 +++
ExamTemplate/Web/Views/Account/Profile.cshtml | 27 +++++
ExamTemplate/Web/Views/Account/Register.cshtml | 20 ++++
ExamTemplate/Web/Views/Shared/_Navbar.cshtml | 8 +-
ExamTemplate/Web/Views/User/EditProfile.cshtml | 20 ----
ExamTemplate/Web/Views/User/Login.cshtml | 14 ---
ExamTemplate/Web/Views/User/Profile.cshtml | 27 -----
ExamTemplate/Web/Views/User/Register.cshtml | 20 ----
17 files changed, 260 insertions(+), 259 deletions(-)
create mode 100644 ExamTemplate/Common/RoleConst.cs
delete mode 100644 ExamTemplate/Data/Models/Role.cs
create mode 100644 ExamTemplate/Web/Controllers/AccountController.cs
delete mode 100644 ExamTemplate/Web/Controllers/UserController.cs
create mode 100644 ExamTemplate/Web/Views/Account/Edit.cshtml
create mode 100644 ExamTemplate/Web/Views/Account/Login.cshtml
create mode 100644 ExamTemplate/Web/Views/Account/Profile.cshtml
create mode 100644 ExamTemplate/Web/Views/Account/Register.cshtml
delete mode 100644 ExamTemplate/Web/Views/User/EditProfile.cshtml
delete mode 100644 ExamTemplate/Web/Views/User/Login.cshtml
delete mode 100644 ExamTemplate/Web/Views/User/Profile.cshtml
delete mode 100644 ExamTemplate/Web/Views/User/Register.cshtml
diff --git a/ExamTemplate/Common/RoleConst.cs b/ExamTemplate/Common/RoleConst.cs
new file mode 100644
index 0000000..3f0dfb7
--- /dev/null
+++ b/ExamTemplate/Common/RoleConst.cs
@@ -0,0 +1,8 @@
+namespace ExamTemplate.Common
+{
+ public static class RoleConst
+ {
+ public static string User = "User";
+ public static string Admin = "Administrator";
+ }
+}
diff --git a/ExamTemplate/Data/Models/Role.cs b/ExamTemplate/Data/Models/Role.cs
deleted file mode 100644
index 9a23f13..0000000
--- a/ExamTemplate/Data/Models/Role.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System;
-using System.Collections.Generic;
-using Microsoft.AspNetCore.Identity;
-using System.ComponentModel.DataAnnotations.Schema;
-
-namespace ExamTemplate.Data.Models
-{
- [Table("Roles")]
- public class Role : IdentityRole
- {
- public static string UserRole = "User";
- public static string AdminRole = "Administrator";
-
- public List Users { get; set; } = new List();
- }
-}
diff --git a/ExamTemplate/Data/Models/User.cs b/ExamTemplate/Data/Models/User.cs
index cb96942..e8aecfa 100644
--- a/ExamTemplate/Data/Models/User.cs
+++ b/ExamTemplate/Data/Models/User.cs
@@ -10,6 +10,5 @@ namespace ExamTemplate.Data.Models
{
public string FirstName { get; set; }
public string LastName { get; set; }
- public List Roles { get; set; } = new List();
}
}
diff --git a/ExamTemplate/Data/TemplateContext.cs b/ExamTemplate/Data/TemplateContext.cs
index ef675a3..268812d 100644
--- a/ExamTemplate/Data/TemplateContext.cs
+++ b/ExamTemplate/Data/TemplateContext.cs
@@ -1,11 +1,12 @@
using System;
using ExamTemplate.Data.Models;
+using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace ExamTemplate.Data
{
- public class TemplateContext : IdentityDbContext
+ public class TemplateContext : IdentityDbContext, Guid>
{
public TemplateContext(DbContextOptions options)
: base(options) { }
@@ -16,10 +17,6 @@ namespace ExamTemplate.Data
.HasIndex(x => x.UserName)
.IsUnique();
- builder.Entity()
- .HasMany(x => x.Roles)
- .WithMany(x => x.Users);
-
base.OnModelCreating(builder);
}
}
diff --git a/ExamTemplate/Services/UserService.cs b/ExamTemplate/Services/UserService.cs
index 90a4bf4..e78443a 100644
--- a/ExamTemplate/Services/UserService.cs
+++ b/ExamTemplate/Services/UserService.cs
@@ -1,4 +1,5 @@
-using System.Security.Claims;
+using System;
+using System.Security.Claims;
using System.Threading.Tasks;
using AutoMapper;
using ExamTemplate.Data;
@@ -15,9 +16,9 @@ namespace ExamTemplate.Services
private readonly TemplateContext _context;
private readonly SignInManager _signInManager;
private readonly UserManager _userManager;
- private readonly RoleManager _roleManager;
+ private readonly RoleManager> _roleManager;
- public UserService(IMapper autoMapper, TemplateContext templateContext, SignInManager signInManager, UserManager userManager, RoleManager roleManager)
+ public UserService(IMapper autoMapper, TemplateContext templateContext, SignInManager signInManager, UserManager userManager, RoleManager> roleManager)
{
this._autoMapper = autoMapper;
this._context = templateContext;
@@ -32,14 +33,9 @@ namespace ExamTemplate.Services
user.PasswordHash = this._userManager.PasswordHasher.HashPassword(user, registerUserServiceModel.Password);
IdentityResult userCreateResult = await this._userManager.CreateAsync(user);
-
- // Many to many relationships with Roles can cause problems,
- // that's why I add the Role to the User and add the User to the Role
IdentityResult addRoleResult = await this._userManager.AddToRoleAsync(user, "User");
- user.Roles.Add(await this._roleManager.FindByNameAsync("User"));
- bool roleAddedSuccessfuly = await this._context.SaveChangesAsync() >= 1;
- return userCreateResult.Succeeded && addRoleResult.Succeeded && roleAddedSuccessfuly;
+ return userCreateResult.Succeeded && addRoleResult.Succeeded;
}
public async Task LoginUserAsync(LoginUserServiceModel loginUserServiceModel)
@@ -57,7 +53,6 @@ namespace ExamTemplate.Services
public async Task GetUserByUsernameAsync(string username)
{
User user = await this._userManager.Users
- .Include(x => x.Roles)
.FirstOrDefaultAsync(x => x.UserName == username);
return this._autoMapper.Map(user);
diff --git a/ExamTemplate/Web/Controllers/AccountController.cs b/ExamTemplate/Web/Controllers/AccountController.cs
new file mode 100644
index 0000000..7fb7ab3
--- /dev/null
+++ b/ExamTemplate/Web/Controllers/AccountController.cs
@@ -0,0 +1,140 @@
+using ExamTemplate.Services;
+using Microsoft.AspNetCore.Mvc;
+using ExamTemplate.Web.Models.User;
+using AutoMapper;
+using ExamTemplate.Services.Models;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authorization;
+
+namespace ExamTemplate.Web.Controllers
+{
+ [Authorize]
+ public class AccountController : Controller
+ {
+ private readonly IMapper _autoMapper;
+ private readonly UserService _userService;
+
+ public AccountController(IMapper autoMapper, UserService userService)
+ {
+ this._autoMapper = autoMapper;
+ this._userService = userService;
+ }
+
+ [HttpGet]
+ [AllowAnonymous]
+ public IActionResult Register()
+ {
+ return View();
+ }
+
+ [HttpPost]
+ [AllowAnonymous]
+ public async Task Register(RegisterUserViewModel registerUserViewModel)
+ {
+ if (!ModelState.IsValid)
+ return View(registerUserViewModel);
+
+ RegisterUserServiceModel registerUserServiceModel = this._autoMapper.Map(registerUserViewModel);
+
+ bool result = await this._userService.RegisterUserAsync(registerUserServiceModel);
+
+ if (result)
+ return RedirectToAction("Index", "Home");
+ else
+ return View();
+ }
+
+ [HttpGet]
+ [AllowAnonymous]
+ public IActionResult Login()
+ {
+ return View();
+ }
+
+ [HttpPost]
+ [AllowAnonymous]
+ public async Task Login(LoginUserViewModel loginUserViewModel)
+ {
+ if (!ModelState.IsValid)
+ return View(loginUserViewModel);
+
+ LoginUserServiceModel loginUserServiceModel = this._autoMapper.Map(loginUserViewModel);
+
+ bool result = await this._userService.LoginUserAsync(loginUserServiceModel);
+
+ if (result)
+ return RedirectToAction("Index", "Home");
+ else
+ return View();
+ }
+
+ [HttpPost]
+ public async Task Logout()
+ {
+ await this._userService.LogoutAsync();
+
+ return RedirectToAction("Login");
+ }
+
+ [HttpGet]
+ [AllowAnonymous]
+ public async Task Profile(string username)
+ {
+ UserServiceModel userServiceModel = await this._userService.GetUserByUsernameAsync(username);
+
+ if (userServiceModel == default(UserServiceModel))
+ return RedirectToAction("Login");
+
+ UserViewModel userViewModel = this._autoMapper.Map(userServiceModel);
+
+ return View(userViewModel);
+ }
+
+ [HttpGet]
+ public async Task Edit()
+ {
+ UserServiceModel userServiceModel = await this._userService.GetUserByClaimsAsync(this.HttpContext.User);
+
+ if (userServiceModel == default(UserServiceModel))
+ return RedirectToAction("Login");
+
+ EditUserViewModel editUserViewModel = this._autoMapper.Map(userServiceModel);
+
+ return View(editUserViewModel);
+ }
+
+ [HttpPost]
+ public async Task Edit(EditUserViewModel editUserViewModel)
+ {
+ if (!await this._userService.IsAuthorizedToModify(HttpContext.User, editUserViewModel.OriginalUsername))
+ return new UnauthorizedResult();
+
+ if (!ModelState.IsValid)
+ return View(editUserViewModel);
+
+ if (!this._userService.IsSignedIn(HttpContext.User))
+ return RedirectToAction("Login");
+
+ UserServiceModel loggedInUser = await this._userService.GetUserByClaimsAsync(HttpContext.User);
+
+ EditUserServiceModel editUserServiceModel = this._autoMapper.Map(editUserViewModel);
+ bool result = await this._userService.EditUserAsync(HttpContext.User, editUserServiceModel);
+
+ if (result)
+ {
+ if (loggedInUser.Username != editUserViewModel.Username)
+ await this._userService.LogoutAsync();
+
+ return RedirectToAction("Profile", new { username = editUserViewModel.Username });
+ }
+ else
+ return RedirectToAction("Profile", new { username = loggedInUser.Username });
+ }
+
+ // [HttpPost]
+ // public async Task DeleteProfile(string username)
+ // {
+ // throw new System.NotImplementedException();
+ // }
+ }
+}
diff --git a/ExamTemplate/Web/Controllers/UserController.cs b/ExamTemplate/Web/Controllers/UserController.cs
deleted file mode 100644
index c7183ca..0000000
--- a/ExamTemplate/Web/Controllers/UserController.cs
+++ /dev/null
@@ -1,131 +0,0 @@
-using ExamTemplate.Services;
-using Microsoft.AspNetCore.Mvc;
-using ExamTemplate.Web.Models.User;
-using AutoMapper;
-using ExamTemplate.Services.Models;
-using System.Threading.Tasks;
-
-namespace ExamTemplate.Web.Controllers
-{
- public class UserController : Controller
- {
- private readonly IMapper _autoMapper;
- private readonly UserService _userService;
-
- public UserController(IMapper autoMapper, UserService userService)
- {
- this._autoMapper = autoMapper;
- this._userService = userService;
- }
-
- [HttpGet]
- [Route("/Register")]
- public IActionResult Register()
- {
- return View();
- }
-
- [HttpPost]
- [Route("/Register")]
- public async Task Register(RegisterUserViewModel registerUserViewModel)
- {
- if (!ModelState.IsValid)
- return View(registerUserViewModel);
-
- RegisterUserServiceModel registerUserServiceModel = this._autoMapper.Map(registerUserViewModel);
-
- bool result = await this._userService.RegisterUserAsync(registerUserServiceModel);
-
- if (result)
- return RedirectToAction("Index", "Home");
- else
- return View();
- }
-
- [HttpGet]
- [Route("/Login")]
- public IActionResult Login()
- {
- return View();
- }
-
- [HttpPost]
- [Route("/Login")]
- public async Task Login(LoginUserViewModel loginUserViewModel)
- {
- if (!ModelState.IsValid)
- return View(loginUserViewModel);
-
- LoginUserServiceModel loginUserServiceModel = this._autoMapper.Map(loginUserViewModel);
-
- bool result = await this._userService.LoginUserAsync(loginUserServiceModel);
-
- if (result)
- return RedirectToAction("Index", "Home");
- else
- return View();
- }
-
- [HttpPost]
- public async Task Logout()
- {
- await this._userService.LogoutAsync();
-
- return RedirectToAction("Login");
- }
-
- [HttpGet]
- [Route("/Profile/{username}")]
- public async Task Profile(string username)
- {
- UserServiceModel userServiceModel = await this._userService.GetUserByUsernameAsync(username);
-
- if (userServiceModel == default(UserServiceModel))
- return RedirectToAction("Login");
-
- UserViewModel userViewModel = this._autoMapper.Map(userServiceModel);
-
- return View(userViewModel);
- }
-
- [HttpGet]
- [Route("/EditProfile")]
- public async Task EditProfile()
- {
- UserServiceModel userServiceModel = await this._userService.GetUserByClaimsAsync(this.HttpContext.User);
-
- if (userServiceModel == default(UserServiceModel))
- return RedirectToAction("Login");
-
- EditUserViewModel editUserViewModel = this._autoMapper.Map(userServiceModel);
-
- return View(editUserViewModel);
- }
-
- [HttpPost]
- [Route("/EditProfile")]
- public async Task EditProfile(EditUserViewModel editUserViewModel)
- {
- if (!ModelState.IsValid)
- return View(editUserViewModel);
-
- if (!this._userService.IsSignedIn(HttpContext.User))
- return RedirectToAction("Login");
-
- UserServiceModel loggedInUser = await this._userService.GetUserByClaimsAsync(HttpContext.User);
-
- EditUserServiceModel editUserServiceModel = this._autoMapper.Map(editUserViewModel);
- bool result = await this._userService.EditUserAsync(HttpContext.User, editUserServiceModel);
-
- if (result)
- {
- if (loggedInUser.Username != editUserViewModel.Username)
- await this._userService.LogoutAsync();
-
- return RedirectToAction("Profile", new { username = editUserViewModel.Username });
- }
- else
- return RedirectToAction("Profile", new { username = loggedInUser.Username });
- }
- }
-}
diff --git a/ExamTemplate/Web/Startup.cs b/ExamTemplate/Web/Startup.cs
index 0754bff..00d94c0 100644
--- a/ExamTemplate/Web/Startup.cs
+++ b/ExamTemplate/Web/Startup.cs
@@ -1,5 +1,6 @@
using System;
using System.Linq;
+using ExamTemplate.Common;
using ExamTemplate.Data;
using ExamTemplate.Data.Models;
using ExamTemplate.Services;
@@ -11,9 +12,8 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
-namespace Web
{
- public class Startup
+ public class Startup
{
public Startup(IConfiguration configuration)
{
@@ -41,10 +41,19 @@ namespace Web
options.UseNpgsql(this.Configuration.GetConnectionString("LocalDBConnection")));
// Needed for SignInManager and UserManager
- services.AddIdentity()
- .AddRoles()
+ services.AddIdentity>(options =>
+ {
+ options.SignIn.RequireConfirmedAccount = false;
+
+ // Password settings
+ options.Password.RequireDigit = false;
+ options.Password.RequireLowercase = false;
+ options.Password.RequireNonAlphanumeric = false;
+ options.Password.RequireUppercase = false;
+ options.Password.RequiredLength = 3;
+ options.Password.RequiredUniqueChars = 0;
+ }).AddRoles>()
.AddEntityFrameworkStores();
-
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@@ -65,8 +74,8 @@ namespace Web
app.UseRouting();
- app.UseAuthorization();
app.UseAuthentication();
+ app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
@@ -85,15 +94,15 @@ namespace Web
dbContext.Database.Migrate();
- var roleManager = (RoleManager)serviceScope.ServiceProvider.GetService(typeof(RoleManager));
- if (!dbContext.Roles.Any(x => x.Name == Role.UserRole))
+ var roleManager = (RoleManager>)serviceScope.ServiceProvider.GetService(typeof(RoleManager>));
+ if (!dbContext.Roles.Any(x => x.Name == RoleConst.User))
{
- Role userRole = new() { Name = Role.UserRole };
+ IdentityRole userRole = new() { Name = RoleConst.User };
roleManager.CreateAsync(userRole).Wait();
}
- if (!dbContext.Roles.Any(x => x.Name == Role.AdminRole))
+ if (!dbContext.Roles.Any(x => x.Name == RoleConst.Admin))
{
- Role adminRole = new() { Name = Role.AdminRole };
+ IdentityRole adminRole = new() { Name = RoleConst.Admin };
roleManager.CreateAsync(adminRole).Wait();
}
diff --git a/ExamTemplate/Web/Views/Account/Edit.cshtml b/ExamTemplate/Web/Views/Account/Edit.cshtml
new file mode 100644
index 0000000..da08d9a
--- /dev/null
+++ b/ExamTemplate/Web/Views/Account/Edit.cshtml
@@ -0,0 +1,20 @@
+@model EditUserViewModel
+@{
+ ViewData["Title"] = "Edit Profile";
+}
+
+
diff --git a/ExamTemplate/Web/Views/Account/Login.cshtml b/ExamTemplate/Web/Views/Account/Login.cshtml
new file mode 100644
index 0000000..688c547
--- /dev/null
+++ b/ExamTemplate/Web/Views/Account/Login.cshtml
@@ -0,0 +1,14 @@
+@model ExamTemplate.Web.Models.User.LoginUserViewModel
+@{
+ ViewData["Title"] = "Login";
+}
+
+
diff --git a/ExamTemplate/Web/Views/Account/Profile.cshtml b/ExamTemplate/Web/Views/Account/Profile.cshtml
new file mode 100644
index 0000000..c6f3e5c
--- /dev/null
+++ b/ExamTemplate/Web/Views/Account/Profile.cshtml
@@ -0,0 +1,27 @@
+@using Microsoft.AspNetCore.Identity
+
+@inject SignInManager SignInManager
+@inject UserManager UserManager
+
+@model UserViewModel
+@{
+ ViewData["Title"] = Model.Username + "'s Profile";
+}
+
+
+
+ @Model.FirstName @Model.LastName
+
+
+ @Model.Username
+
+ @if (SignInManager.IsSignedIn(User))
+ {
+ @if(UserManager.GetUserName(User) == Model.Username)
+ {
+
+ }
+ }
+
diff --git a/ExamTemplate/Web/Views/Account/Register.cshtml b/ExamTemplate/Web/Views/Account/Register.cshtml
new file mode 100644
index 0000000..d255287
--- /dev/null
+++ b/ExamTemplate/Web/Views/Account/Register.cshtml
@@ -0,0 +1,20 @@
+@model ExamTemplate.Web.Models.User.RegisterUserViewModel
+@{
+ ViewData["Title"] = "Register";
+}
+
+
diff --git a/ExamTemplate/Web/Views/Shared/_Navbar.cshtml b/ExamTemplate/Web/Views/Shared/_Navbar.cshtml
index 7ae8f50..0ec5c4d 100644
--- a/ExamTemplate/Web/Views/Shared/_Navbar.cshtml
+++ b/ExamTemplate/Web/Views/Shared/_Navbar.cshtml
@@ -13,18 +13,18 @@
diff --git a/ExamTemplate/Web/Views/User/EditProfile.cshtml b/ExamTemplate/Web/Views/User/EditProfile.cshtml
deleted file mode 100644
index da08d9a..0000000
--- a/ExamTemplate/Web/Views/User/EditProfile.cshtml
+++ /dev/null
@@ -1,20 +0,0 @@
-@model EditUserViewModel
-@{
- ViewData["Title"] = "Edit Profile";
-}
-
-
diff --git a/ExamTemplate/Web/Views/User/Login.cshtml b/ExamTemplate/Web/Views/User/Login.cshtml
deleted file mode 100644
index 7cb5ac5..0000000
--- a/ExamTemplate/Web/Views/User/Login.cshtml
+++ /dev/null
@@ -1,14 +0,0 @@
-@model ExamTemplate.Web.Models.User.LoginUserViewModel
-@{
- ViewData["Title"] = "Login";
-}
-
-
diff --git a/ExamTemplate/Web/Views/User/Profile.cshtml b/ExamTemplate/Web/Views/User/Profile.cshtml
deleted file mode 100644
index 4120766..0000000
--- a/ExamTemplate/Web/Views/User/Profile.cshtml
+++ /dev/null
@@ -1,27 +0,0 @@
-@using Microsoft.AspNetCore.Identity
-
-@inject SignInManager SignInManager
-@inject UserManager UserManager
-
-@model UserViewModel
-@{
- ViewData["Title"] = Model.Username + "'s Profile";
-}
-
-
-
- @Model.FirstName @Model.LastName
-
-
- @Model.Username
-
- @if (SignInManager.IsSignedIn(User))
- {
- @if(UserManager.GetUserName(User) == Model.Username)
- {
-
- }
- }
-
diff --git a/ExamTemplate/Web/Views/User/Register.cshtml b/ExamTemplate/Web/Views/User/Register.cshtml
deleted file mode 100644
index 3b7f6d9..0000000
--- a/ExamTemplate/Web/Views/User/Register.cshtml
+++ /dev/null
@@ -1,20 +0,0 @@
-@model ExamTemplate.Web.Models.User.RegisterUserViewModel
-@{
- ViewData["Title"] = "Register";
-}
-
-
--
cgit v1.2.3