forked from ReiMerc/skantravels
Updated UserModel, UpdatePassword made
This commit is contained in:
parent
bb44d2bc56
commit
f1327571e6
@ -77,9 +77,6 @@ namespace API.Application.Users.Commands
|
|||||||
CreatedAt = DateTime.UtcNow.AddHours(2),
|
CreatedAt = DateTime.UtcNow.AddHours(2),
|
||||||
UpdatedAt = DateTime.UtcNow.AddHours(2),
|
UpdatedAt = DateTime.UtcNow.AddHours(2),
|
||||||
HashedPassword = hashedPassword,
|
HashedPassword = hashedPassword,
|
||||||
Salt = salt,
|
|
||||||
PasswordBackdoor = signUpDTO.Password,
|
|
||||||
// Only for educational purposes, not in the final product!
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,57 @@
|
|||||||
namespace API.Application.Users.Commands
|
using API.Models;
|
||||||
|
using API.Persistence.Repositories;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace API.Application.Users.Commands
|
||||||
{
|
{
|
||||||
public class UpdateUserPassword
|
public class UpdateUserPassword
|
||||||
{
|
{
|
||||||
|
private readonly IUserRepository _repository;
|
||||||
|
|
||||||
|
public UpdateUserPassword(IUserRepository repository)
|
||||||
|
{
|
||||||
|
_repository = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IActionResult> Handle(ChangePasswordDTO changePasswordDTO)
|
||||||
|
{
|
||||||
|
if (!IsPasswordSecure(changePasswordDTO.NewPassword))
|
||||||
|
{
|
||||||
|
return new ConflictObjectResult(new { message = "New Password is not secure." });
|
||||||
|
}
|
||||||
|
|
||||||
|
User currentUser = await _repository.QueryUserByIdAsync(changePasswordDTO.Id);
|
||||||
|
if (currentUser == null || !BCrypt.Net.BCrypt.Verify(changePasswordDTO.OldPassword, currentUser.HashedPassword))
|
||||||
|
{
|
||||||
|
return new UnauthorizedObjectResult(new { message = "Old Password is incorrect" });
|
||||||
|
}
|
||||||
|
string hashedPassword = BCrypt.Net.BCrypt.HashPassword(changePasswordDTO.NewPassword);
|
||||||
|
|
||||||
|
currentUser.HashedPassword = hashedPassword;
|
||||||
|
|
||||||
|
bool success = await _repository.UpdateUserPasswordAsync(currentUser);
|
||||||
|
if (success)
|
||||||
|
return new OkResult();
|
||||||
|
else
|
||||||
|
return new StatusCodeResult(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsPasswordSecure(string password)
|
||||||
|
{
|
||||||
|
var hasUpperCase = new Regex(@"[A-Z]+");
|
||||||
|
var hasLowerCase = new Regex(@"[a-z]+");
|
||||||
|
var hasDigits = new Regex(@"[0-9]+");
|
||||||
|
var hasSpecialChar = new Regex(@"[\W_]+");
|
||||||
|
var hasMinimum8Chars = new Regex(@".{8,}");
|
||||||
|
|
||||||
|
return hasUpperCase.IsMatch(password)
|
||||||
|
&& hasLowerCase.IsMatch(password)
|
||||||
|
&& hasDigits.IsMatch(password)
|
||||||
|
&& hasSpecialChar.IsMatch(password)
|
||||||
|
&& hasMinimum8Chars.IsMatch(password);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using API.Models;
|
using API.Models;
|
||||||
using API.Persistence.Repositories;
|
using API.Persistence.Repositories;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.VisualStudio.Web.CodeGenerators.Mvc.Templates.BlazorIdentity.Pages.Manage;
|
using Microsoft.VisualStudio.Web.CodeGenerators.Mvc.Templates.BlazorIdentity.Pages.Manage;
|
||||||
|
|
||||||
namespace API.Application.Users.Queries
|
namespace API.Application.Users.Queries
|
||||||
@ -13,10 +14,15 @@ namespace API.Application.Users.Queries
|
|||||||
_repository = repository;
|
_repository = repository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<UserDTO> Handle(string id)
|
public async Task<ActionResult<UserDTO>> Handle(string id)
|
||||||
{
|
{
|
||||||
User user = await _repository.QueryUserByIdAsync(id);
|
User user = await _repository.QueryUserByIdAsync(id);
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return new ConflictObjectResult(new { message = "No user on given Id" });
|
||||||
|
}
|
||||||
|
|
||||||
UserDTO userDTO = new UserDTO
|
UserDTO userDTO = new UserDTO
|
||||||
{
|
{
|
||||||
Id = user.Id,
|
Id = user.Id,
|
||||||
|
@ -20,6 +20,7 @@ namespace API.Controllers
|
|||||||
private readonly QueryUserById _queryUserById;
|
private readonly QueryUserById _queryUserById;
|
||||||
private readonly CreateUser _createUser;
|
private readonly CreateUser _createUser;
|
||||||
private readonly UpdateUser _updateUser;
|
private readonly UpdateUser _updateUser;
|
||||||
|
private readonly UpdateUserPassword _updateUserPassword;
|
||||||
private readonly DeleteUser _deleteUser;
|
private readonly DeleteUser _deleteUser;
|
||||||
private readonly LoginUser _loginUser;
|
private readonly LoginUser _loginUser;
|
||||||
|
|
||||||
@ -28,6 +29,7 @@ namespace API.Controllers
|
|||||||
QueryUserById queryUserById,
|
QueryUserById queryUserById,
|
||||||
CreateUser createUser,
|
CreateUser createUser,
|
||||||
UpdateUser updateUser,
|
UpdateUser updateUser,
|
||||||
|
UpdateUserPassword updateUserPassword,
|
||||||
DeleteUser deleteUser,
|
DeleteUser deleteUser,
|
||||||
LoginUser loginUser)
|
LoginUser loginUser)
|
||||||
{
|
{
|
||||||
@ -35,18 +37,17 @@ namespace API.Controllers
|
|||||||
_queryUserById = queryUserById;
|
_queryUserById = queryUserById;
|
||||||
_createUser = createUser;
|
_createUser = createUser;
|
||||||
_updateUser = updateUser;
|
_updateUser = updateUser;
|
||||||
|
_updateUserPassword = updateUserPassword;
|
||||||
_deleteUser = deleteUser;
|
_deleteUser = deleteUser;
|
||||||
_loginUser = loginUser;
|
_loginUser = loginUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST: api/Users/login
|
|
||||||
[HttpPost("login")]
|
[HttpPost("login")]
|
||||||
public async Task<IActionResult> Login(LoginDTO login)
|
public async Task<IActionResult> Login(LoginDTO login)
|
||||||
{
|
{
|
||||||
return await _loginUser.Handle(login);
|
return await _loginUser.Handle(login);
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET: api/Users
|
|
||||||
[Authorize]
|
[Authorize]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<ActionResult<List<UserDTO>>> GetUsers()
|
public async Task<ActionResult<List<UserDTO>>> GetUsers()
|
||||||
@ -54,8 +55,7 @@ namespace API.Controllers
|
|||||||
return await _queryAllUsers.Handle();
|
return await _queryAllUsers.Handle();
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET: api/Users/5
|
|
||||||
[Authorize]
|
|
||||||
[HttpGet("{id}")]
|
[HttpGet("{id}")]
|
||||||
public async Task<ActionResult<UserDTO>> GetUser(string id)
|
public async Task<ActionResult<UserDTO>> GetUser(string id)
|
||||||
{
|
{
|
||||||
@ -63,25 +63,26 @@ namespace API.Controllers
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PUT: api/Users/5
|
|
||||||
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
|
|
||||||
[Authorize]
|
[Authorize]
|
||||||
[HttpPut("{id}")]
|
[HttpPut]
|
||||||
public async Task<IActionResult> PutUser(UserDTO userDTO)
|
public async Task<IActionResult> PutUser(UserDTO userDTO)
|
||||||
{
|
{
|
||||||
return await _updateUser.Handle(userDTO);
|
return await _updateUser.Handle(userDTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST: api/Users
|
[Authorize]
|
||||||
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
|
[HttpPut("password")]
|
||||||
|
public async Task<IActionResult> PutUserPassword(ChangePasswordDTO changePasswordDTO)
|
||||||
|
{
|
||||||
|
return await _updateUserPassword.Handle(changePasswordDTO);
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public async Task<ActionResult<Guid>> PostUser(SignUpDTO signUpDTO)
|
public async Task<ActionResult<Guid>> PostUser(SignUpDTO signUpDTO)
|
||||||
{
|
{
|
||||||
return await _createUser.Handle(signUpDTO);
|
return await _createUser.Handle(signUpDTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// DELETE: api/Users/5
|
|
||||||
[Authorize]
|
[Authorize]
|
||||||
[HttpDelete("{id}")]
|
[HttpDelete("{id}")]
|
||||||
public async Task<IActionResult> DeleteUser(string id)
|
public async Task<IActionResult> DeleteUser(string id)
|
||||||
|
54
API/Migrations/20240816102314_removedSaltAndBackdoor.Designer.cs
generated
Normal file
54
API/Migrations/20240816102314_removedSaltAndBackdoor.Designer.cs
generated
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using API;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace API.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(AppDBContext))]
|
||||||
|
[Migration("20240816102314_removedSaltAndBackdoor")]
|
||||||
|
partial class removedSaltAndBackdoor
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "8.0.7");
|
||||||
|
|
||||||
|
modelBuilder.Entity("API.Models.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("HashedPassword")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Password")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UpdatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
40
API/Migrations/20240816102314_removedSaltAndBackdoor.cs
Normal file
40
API/Migrations/20240816102314_removedSaltAndBackdoor.cs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace API.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class removedSaltAndBackdoor : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "PasswordBackdoor",
|
||||||
|
table: "Users");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Salt",
|
||||||
|
table: "Users");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "PasswordBackdoor",
|
||||||
|
table: "Users",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "Salt",
|
||||||
|
table: "Users",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -35,14 +35,6 @@ namespace API.Migrations
|
|||||||
b.Property<string>("Password")
|
b.Property<string>("Password")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
b.Property<string>("PasswordBackdoor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("Salt")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<DateTime>("UpdatedAt")
|
b.Property<DateTime>("UpdatedAt")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
@ -8,8 +8,6 @@ public class User : BaseModel
|
|||||||
public string? Username { get; set; }
|
public string? Username { get; set; }
|
||||||
public string? Password { get; set; }
|
public string? Password { get; set; }
|
||||||
public string HashedPassword { get; set; }
|
public string HashedPassword { get; set; }
|
||||||
public string PasswordBackdoor { get; set; }
|
|
||||||
public string Salt { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class UserDTO
|
public class UserDTO
|
||||||
@ -30,5 +28,12 @@ public class SignUpDTO
|
|||||||
public string Email { get; set; }
|
public string Email { get; set; }
|
||||||
public string Username { get; set; }
|
public string Username { get; set; }
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ChangePasswordDTO
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public string OldPassword { get; set; }
|
||||||
|
public string NewPassword { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -10,5 +10,6 @@ namespace API.Persistence.Repositories
|
|||||||
Task<User> QueryUserByIdAsync(string id);
|
Task<User> QueryUserByIdAsync(string id);
|
||||||
Task<User> QueryUserByEmailAsync(string email);
|
Task<User> QueryUserByEmailAsync(string email);
|
||||||
Task<bool> UpdateUserAsync(User user);
|
Task<bool> UpdateUserAsync(User user);
|
||||||
|
Task<bool> UpdateUserPasswordAsync(User user);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -21,7 +21,6 @@ namespace API.Persistence.Repositories
|
|||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
|
|
||||||
return new User();
|
return new User();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,6 +57,21 @@ namespace API.Persistence.Repositories
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<bool> UpdateUserPasswordAsync(User user)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_context.Entry(user).State = EntityState.Modified;
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<bool> DeleteUserAsync(string id)
|
public async Task<bool> DeleteUserAsync(string id)
|
||||||
{
|
{
|
||||||
var user = await _context.Users.FindAsync(id);
|
var user = await _context.Users.FindAsync(id);
|
||||||
|
@ -36,6 +36,7 @@ namespace API
|
|||||||
builder.Services.AddScoped<QueryUserById>();
|
builder.Services.AddScoped<QueryUserById>();
|
||||||
builder.Services.AddScoped<CreateUser>();
|
builder.Services.AddScoped<CreateUser>();
|
||||||
builder.Services.AddScoped<UpdateUser>();
|
builder.Services.AddScoped<UpdateUser>();
|
||||||
|
builder.Services.AddScoped<UpdateUserPassword>();
|
||||||
builder.Services.AddScoped<DeleteUser>();
|
builder.Services.AddScoped<DeleteUser>();
|
||||||
builder.Services.AddScoped<LoginUser>();
|
builder.Services.AddScoped<LoginUser>();
|
||||||
builder.Services.AddScoped<IUserRepository, UserRepository>();
|
builder.Services.AddScoped<IUserRepository, UserRepository>();
|
||||||
|
Loading…
Reference in New Issue
Block a user