Compare commits

...

4 Commits

7 changed files with 233 additions and 5 deletions

View File

@ -1,4 +1,5 @@
using Contracts.BindingModels;
using BusinessLogic.Tools;
using Contracts.BindingModels;
using Contracts.BusinessLogicContracts;
using Contracts.Converters;
using Contracts.Exceptions;
@ -28,7 +29,10 @@ namespace BusinessLogic.BusinessLogic
public UserViewModel Create(UserBindingModel model)
{
ArgumentNullException.ThrowIfNull(model);
// Проверяем пароль
_validatePassword(model.Password);
// Хешируем пароль
model.PasswordHash = PasswordHasher.Hash(model.Password);
var user = _userStorage.Insert(model);
if (user is null)
{
@ -46,7 +50,7 @@ namespace BusinessLogic.BusinessLogic
var user = _userStorage.Delete(model);
if (user is null)
{
throw new Exception("Update operation failed.");
throw new ElementNotFoundException();
}
return UserConverter.ToView(user);
@ -85,6 +89,11 @@ namespace BusinessLogic.BusinessLogic
{
ArgumentNullException.ThrowIfNull(model);
if (model.Password is not null)
{
_validatePassword(model.Password);
model.PasswordHash = PasswordHasher.Hash(model.Password);
}
var user = _userStorage.Update(model);
if (user is null)
{
@ -92,5 +101,32 @@ namespace BusinessLogic.BusinessLogic
}
return UserConverter.ToView(user);
}
public UserViewModel Login(UserBindingModel model)
{
ArgumentNullException.ThrowIfNull(model);
var user = _userStorage.GetElement(new() { Email = model.Email });
if (user is null)
{
throw new ElementNotFoundException();
}
// Проверяем пароль
_validatePassword(model.Password);
if (PasswordHasher.Verify(model.Password, user.PasswordHash))
{
throw new AccountException("The passwords don't match.");
}
return UserConverter.ToView(user);
}
public void _validatePassword(string? password)
{
if (string.IsNullOrWhiteSpace(password))
{
throw new AccountException("The password is null.");
}
}
}
}

View File

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace BusinessLogic.Tools
{
internal class PasswordHasher
{
/// <summary>
/// Хеширует с использование SHA256
/// </summary>
/// <param name="password">Пароль</param>
/// <returns>Хеш пароля</returns>
public static string Hash(string password)
{
using (SHA256 sha256 = SHA256.Create())
{
byte[] bytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(password));
return Convert.ToBase64String(bytes);
}
}
/// <summary>
/// Проверяет на соответствие пароля и его хеша
/// </summary>
/// <param name="password">Пароль</param>
/// <param name="passHash">Хеш пароля</param>
/// <returns></returns>
public static bool Verify(string password, string passHash)
{
var hash = Hash(password);
return hash == passHash;
}
}
}

View File

@ -13,6 +13,7 @@ namespace Contracts.BindingModels
public string SecondName { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public string PasswordHash { get; set; } = string.Empty;
public string? Password { get; set; }
public DateTime Birthday { get; set; }
public RoleBindingModel Role { get; set; } = null!;
}

View File

@ -11,6 +11,8 @@ namespace Contracts.BusinessLogicContracts
{
public interface IUserLogic
{
UserViewModel Login(UserBindingModel model);
UserViewModel Create(UserBindingModel model);
UserViewModel Update(UserBindingModel model);

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Contracts.Exceptions
{
public class AccountException : Exception
{
public AccountException()
{
}
public AccountException(string message) : base(message)
{
}
public AccountException(string message, Exception inner) : base(message, inner)
{
}
}
}

View File

@ -32,7 +32,7 @@ namespace RestAPI.Controllers
}
catch (ElementNotFoundException ex)
{
_logger.LogInformation(ex, "Element not found");
_logger.LogInformation(ex, "Role not found");
return Results.NoContent();
}
catch (Exception ex)
@ -87,7 +87,7 @@ namespace RestAPI.Controllers
}
}
[HttpPut]
[HttpPatch]
public IResult Update([FromBody] RoleBindingModel model)
{
try

View File

@ -0,0 +1,128 @@
using BusinessLogic.BusinessLogic;
using Contracts.BindingModels;
using Contracts.BusinessLogicContracts;
using Contracts.Exceptions;
using Contracts.SearchModels;
using Microsoft.AspNetCore.Mvc;
namespace RestAPI.Controllers
{
[Route("[controller]/[action]")]
[ApiController]
public class UserController
{
private readonly ILogger _logger;
private readonly IUserLogic _userLogic;
public UserController(ILogger<UserController> logger, IUserLogic userLogic)
{
_userLogic = userLogic;
_logger = logger;
}
[HttpPost]
public IResult Login([FromBody] UserBindingModel model)
{
try
{
var res = _userLogic.Login(model);
return Results.Ok(res);
}
catch (ElementNotFoundException ex)
{
_logger.LogInformation(ex, "User not found");
return Results.NoContent();
}
catch (AccountException ex)
{
_logger.LogWarning(ex, "Wrong login data");
return Results.BadRequest(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error get user");
return Results.Problem(ex.Message);
}
}
[HttpPost]
public IResult Registration([FromBody] UserBindingModel model)
{
try
{
var res = _userLogic.Login(model);
return Results.Ok(res);
}
catch (AccountException ex)
{
_logger.LogWarning(ex, "Wrong registration data");
return Results.BadRequest(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error create user");
return Results.Problem(ex.Message);
}
}
[HttpGet]
public IResult Get([FromQuery] UserSearchModel model)
{
try
{
var res = _userLogic.ReadElement(model);
return Results.Ok(res);
}
catch (ElementNotFoundException ex)
{
_logger.LogInformation(ex, "User not found");
return Results.NoContent();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error get user");
return Results.Problem(ex.Message);
}
}
[HttpPatch]
public IResult Update([FromBody] UserBindingModel model)
{
try
{
var res = _userLogic.Update(model);
return Results.Ok(res);
}
catch (AccountException ex)
{
_logger.LogWarning(ex, "Wrong update data");
return Results.BadRequest(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error update user");
return Results.Problem(ex.Message);
}
}
[HttpDelete]
public IResult Delete(Guid id)
{
try
{
var res = _userLogic.Delete(new() { Id = id });
return Results.Ok(res);
}
catch (ElementNotFoundException ex)
{
_logger.LogInformation(ex, "User not found");
return Results.NoContent();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error delete user");
return Results.Problem(ex.Message);
}
}
}
}