Убрали зависимость Security к десктопному приложению

This commit is contained in:
kotcheshir73 2021-03-28 10:23:26 +04:00
parent 525add0260
commit 8ad72cd50d
17 changed files with 168 additions and 269 deletions

View File

@ -4,20 +4,56 @@ using ModelTools.Interfaces;
using ModelTools.Models;
using SecurityBusinessLogic.BusinessLogics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace DatabaseCore
{
public class SecurityManager : ISecurityManager
{
private readonly int _countDayToBanned = 3;
private readonly int _countMaxAttempt = 3;
private static SecurityManager _securityManager;
private static readonly object _lockObject = new();
private SecurityManager() { }
/// <summary>
/// Singleton для класса
/// </summary>
public static SecurityManager GetInstance
{
get
{
if (_securityManager == null)
{
lock (_lockObject)
{
_securityManager = new SecurityManager();
}
}
return _securityManager;
}
}
public Guid? User { get; set; }
public List<Guid> Roles { get; set; }
public string ErrorMessage { get; set; }
public bool IsAuth => User != null;
public bool CheckAccess(SecurityManagerCheckAccessModel model)
{
using var context = DatabaseManager.GetContext;
Access access;
Access access = null;
if (model != null)
{
// простой просмотр возможен
@ -26,9 +62,9 @@ namespace DatabaseCore
return true;
}
// если не указан идентификатор пользователя, то смотрим, может он авторизован
if (!model.Model.UserId.HasValue && UserManager.GetInstance.User != null)
if (!model.Model.UserId.HasValue && User.HasValue)
{
model.Model.UserId = UserManager.GetInstance.UserId;
model.Model.UserId = User.Value;
}
var roles = context.UserRoles.Where(x => x.UserId == model.Model.UserId).Select(x => x.Role).OrderByDescending(x => x.RolePriority).ToList();
@ -39,9 +75,9 @@ namespace DatabaseCore
}
access = context.Accesses.FirstOrDefault(a => a.AccessOperation == model.Operation && roles.Contains(a.Role));
}
else
else if (Roles != null)
{
access = context.Accesses.FirstOrDefault(a => a.AccessOperation == model.Operation && UserManager.GetInstance.Roles.Contains(a.RoleId));
access = context.Accesses.FirstOrDefault(a => a.AccessOperation == model.Operation && Roles.Contains(a.RoleId));
}
if (access != null)
{
@ -121,5 +157,85 @@ namespace DatabaseCore
transaction.Commit();
}
public async Task LoginAsync(string login, string password)
{
var passwordHash = GetPasswordHash(password);
using var context = DatabaseManager.GetContext;
var user = context.Users.FirstOrDefault(x => x.UserName == login && x.PasswordHash == passwordHash);
await CheckUserAsync(login, user, context);
user.DateLastVisit = DateTime.Now;
user.CountAttempt = 0;
await context.SaveChangesAsync();
User = user.Id;
Roles = context.UserRoles.Where(x => x.UserId == user.Id).Select(x => x.RoleId).ToList();
}
public async Task LogoutAsync()
{
await Task.Run(() =>
{
User = null;
Roles = null;
});
}
public async Task ChangePassword(string login, string oldPassword, string newPassword)
{
using var context = DatabaseManager.GetContext;
var user = context.Users.FirstOrDefault(x => x.UserName == login && x.PasswordHash == GetPasswordHash(oldPassword));
await CheckUserAsync(login, user, context);
user.PasswordHash = GetPasswordHash(newPassword);
await context.SaveChangesAsync();
}
/// <summary>
/// Получение хеша пароля
/// </summary>
/// <param name="password"></param>
/// <returns></returns>
private static string GetPasswordHash(string password) => Encoding.ASCII.GetString((new MD5CryptoServiceProvider()).ComputeHash(Encoding.ASCII.GetBytes(password)));
/// <summary>
/// Проверка пользователя при авторизации и при смене пароля
/// </summary>
/// <param name="login"></param>
/// <param name="user"></param>
/// <param name="context"></param>
/// <returns></returns>
private async Task CheckUserAsync(string login, User user, DatabaseContext context)
{
if (user == null)
{
user = context.Users.FirstOrDefault(x => x.UserName == login);
if (user != null)
{
user.CountAttempt++;
if (user.CountAttempt > _countMaxAttempt)
{
user.IsBanned = true;
user.DateBanned = DateTime.Now;
await context.SaveChangesAsync();
throw new Exception($"Введен неверный логин/пароль? учетная запись заблоикрована на {_countDayToBanned} дней(я)");
}
}
throw new Exception("Введен неверный логин/пароль");
}
if (user.IsBanned)
{
if (user.DateBanned.Value.AddDays(_countDayToBanned) > DateTime.Now)
{
user.IsBanned = false;
await context.SaveChangesAsync();
}
else
{
throw new Exception("Пользователь заблокирован");
}
}
}
}
}

View File

@ -1,9 +1,27 @@
using ModelTools.Models;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ModelTools.Interfaces
{
public interface ISecurityManager
{
/// <summary>
/// Аутентифицированный пользователь
/// </summary>
public Guid? User { get; set; }
/// <summary>
/// Список ролей аутентифицированного пользователь
/// </summary>
public List<Guid> Roles { get; set; }
/// <summary>
/// Выполнена ли аутентификация
/// </summary>
public bool IsAuth { get; }
/// <summary>
/// Сообщение с причиной не получения доступа
/// </summary>
@ -20,5 +38,27 @@ namespace ModelTools.Interfaces
/// Проверка наличия старотвых данных для работы с ситемой
/// </summary>
void CheckStartDataSource();
/// <summary>
/// Аутентификация пользователя
/// </summary>
/// <param name="login"></param>
/// <param name="password"></param>
/// <returns></returns>
Task LoginAsync(string login, string password);
/// <summary>
/// Выход из системы
/// </summary>
/// <returns></returns>
Task LogoutAsync();
/// <summary>
/// Смена пароля
/// </summary>
/// <param name="login"></param>
/// <param name="oldPassword"></param>
/// <param name="newPassword"></param>
Task ChangePassword(string login, string oldPassword, string newPassword);
}
}

View File

@ -16,7 +16,6 @@
<ItemGroup>
<ProjectReference Include="..\Common\DatabaseCore\DatabaseCore.csproj" />
<ProjectReference Include="..\Common\DesktopTools\DesktopTools.csproj" />
<ProjectReference Include="..\Security\SecurityBusinessLogic\SecurityBusinessLogic.csproj" />
</ItemGroup>
<ItemGroup>

View File

@ -1,5 +1,7 @@
using DesktopTools.BusinessLogics;
using ModelTools.BusinessLogics;
using ModelTools.Extensions;
using ModelTools.Interfaces;
using SecurityBusinessLogic.BusinessLogics;
using System;
using System.Collections.Generic;
@ -30,7 +32,8 @@ namespace DepartmentPortalDesctop
}
try
{
Task.WaitAll(Task.Run(async () => await UserManager.GetInstance.LoginAsync(textBoxLogin.Text, textBoxPassword.Text)));
var securityManager = UnityContainerConfigurator.Resolve<ISecurityManager>();
Task.WaitAll(Task.Run(async () => await securityManager.LoginAsync(textBoxLogin.Text, textBoxPassword.Text)));
DialogResult = DialogResult.OK;
Close();
}

View File

@ -27,7 +27,7 @@ namespace DepartmentPortalDesctop
var form = new FormEnter();
if (form.ShowDialog() == DialogResult.OK && UserManager.GetInstance.IsAuth)
if (form.ShowDialog() == DialogResult.OK && securityManager.IsAuth)
{
Application.Run(UnityContainerConfigurator.Resolve<FormMain>());
}

View File

@ -10,13 +10,6 @@ namespace SecurityBusinessLogic.BindingModels
/// </summary>
public class UserGetBindingModel : GetBindingModel
{
public bool? IsBanned { get; set; }
public string Login { get; set; }
public string Password { get; set; }
public List<Guid> LecturerIds { get; set; }
}
/// <summary>

View File

@ -1,223 +0,0 @@
using ModelTools.BusinessLogics;
using SecurityBusinessLogic.BindingModels;
using SecurityBusinessLogic.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace SecurityBusinessLogic.BusinessLogics
{
/// <summary>
/// Менеджер по работе с пользователем системы
/// </summary>
public class UserManager
{
private readonly int _countDayToBanned = 3;
private readonly int _countMaxAttempt = 3;
private readonly RoleBusinessLogic _roleBusinessLogic;
private readonly UserBusinessLogic _userBusinessLogic;
private static UserManager _userManager;
private static readonly object _lockObject = new();
private UserManager()
{
_roleBusinessLogic = UnityContainerConfigurator.Resolve<RoleBusinessLogic>();
_userBusinessLogic = UnityContainerConfigurator.Resolve<UserBusinessLogic>();
}
public static UserManager GetInstance
{
get
{
if (_userManager == null)
{
lock (_lockObject)
{
_userManager = new UserManager();
}
}
return _userManager;
}
}
/// <summary>
/// Аутентифицированный пользователь
/// </summary>
public UserViewModel User { get; private set; }
/// <summary>
/// Список ролей аутентифицированного пользователь
/// </summary>
public List<Guid> Roles { get; private set; }
/// <summary>
/// Сообщение об ошибке
/// </summary>
public string ErrorMessage { get; private set; }
/// <summary>
/// Идентификатор аутентифицированного пользователь
/// </summary>
public Guid? UserId => User?.Id;
/// <summary>
/// Выполнена ли аутентификация
/// </summary>
public bool IsAuth => User != null;
/// <summary>
/// Аутентификация пользователя
/// </summary>
/// <param name="login"></param>
/// <param name="password"></param>
/// <returns></returns>
public async Task LoginAsync(string login, string password)
{
await Task.Run(() =>
{
UserSetBindingModel model;
var passwordHash = GetPasswordHash(password);
var user = _userBusinessLogic.GetElement(new UserGetBindingModel
{
Login = login,
Password = passwordHash,
SkipCheck = true
});
if (user == null)
{
if(_userBusinessLogic.Errors.Count > 0)
{
throw new Exception(_userBusinessLogic.Errors[0].Message);
}
user = _userBusinessLogic.GetElement(new UserGetBindingModel
{
Login = login,
IsBanned = true,
SkipCheck = true
});
if (user != null)
{
user.CountAttempt++;
if (user.CountAttempt > _countMaxAttempt)
{
user.IsBanned = true;
user.DateBanned = DateTime.Now;
}
model = GetSetBindingModel(user);
model.Password = passwordHash;
_userBusinessLogic.Update(model);
}
if (_userBusinessLogic.Errors.Count > 0)
{
throw new Exception(_userBusinessLogic.Errors[0].Message);
}
throw new Exception("Введен неверный логин/пароль");
}
if (user.IsBanned)
{
if (user.DateBanned.Value.AddDays(_countDayToBanned) > DateTime.Now)
{
user.IsBanned = false;
}
else
{
throw new Exception("Пользователь заблокирован");
}
}
user.DateLastVisit = DateTime.Now;
user.CountAttempt = 0;
model = GetSetBindingModel(user);
model.Password = passwordHash;
_userBusinessLogic.Update(model);
User = user;
Roles = _roleBusinessLogic.GetList(new RoleGetBindingModel { UserId = User.Id }).List.Select(x => x.Id).ToList();
});
}
/// <summary>
/// Выход из системы
/// </summary>
/// <returns></returns>
public async Task LogoutAsync()
{
await Task.Run(() =>
{
User = null;
Roles = null;
});
}
/// <summary>
/// Смена пароля
/// </summary>
/// <param name="login"></param>
/// <param name="oldPassword"></param>
/// <param name="newPassword"></param>
public void ChangePassword(string login, string oldPassword, string newPassword)
{
var user = _userBusinessLogic.GetElement(new UserGetBindingModel
{
Login = login,
Password = GetPasswordHash(oldPassword),
SkipCheck = true
});
if (user == null)
{
throw new Exception("Введен неверный логин/пароль");
}
if (user.IsBanned)
{
throw new Exception("Пользователь забаннен");
}
var model = GetSetBindingModel(user);
model.Password = GetPasswordHash(newPassword);
_userBusinessLogic.Update(model);
}
/// <summary>
/// Получение хеша пароля
/// </summary>
/// <param name="password"></param>
/// <returns></returns>
public static string GetPasswordHash(string password) => Encoding.ASCII.GetString((new MD5CryptoServiceProvider()).ComputeHash(Encoding.ASCII.GetBytes(password)));
/// <summary>
/// Получение модели для сохранения из представления
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
private static UserSetBindingModel GetSetBindingModel(UserViewModel model)
{
return new UserSetBindingModel
{
Id = model.Id,
Login = model.Login,
LecturerId = model.LecturerId,
StudentId = model.StudentId,
EmployeeId = model.EmployeeId,
Avatar = model.Avatar,
IsBanned = model.IsBanned,
DateBanned = model.DateBanned,
CountAttempt = model.CountAttempt,
DateLastVisit = model.DateLastVisit
};
}
}
}

View File

@ -2,7 +2,6 @@
using DatabaseCore.Models.Security;
using ModelTools.BusinessLogics;
using ModelTools.Enums;
using ModelTools.Extensions;
using ModelTools.Models;
using SecurityBusinessLogic.BindingModels;
using SecurityBusinessLogic.Interfaces;
@ -99,35 +98,7 @@ namespace SecurityImplementation.Implementations
return OperationResultModel.Success(Mapper.MapToClass<User, UserViewModel>(entity));
}
if (model.Login.IsNotEmpty() && model.Password.IsNotEmpty())
{
var entity = context.Users.FirstOrDefault(x => x.UserName == model.Login && x.PasswordHash == model.Password);
if (entity == null)
{
return OperationResultModel.Error("Error:", "Элемент не найден", ResultServiceStatusCode.NotFound);
}
return OperationResultModel.Success(Mapper.MapToClass<User, UserViewModel>(entity));
}
if (model.Login.IsNotEmpty() && model.IsBanned.HasValue)
{
var entity = context.Users.FirstOrDefault(x => x.UserName == model.Login && x.IsBanned == model.IsBanned.Value);
if (entity == null)
{
return OperationResultModel.Error("Error:", "Элемент не найден", ResultServiceStatusCode.NotFound);
}
return OperationResultModel.Success(Mapper.MapToClass<User, UserViewModel>(entity));
}
var query = context.Users.Where(x => !x.IsDeleted).AsQueryable();
if (model.IsBanned.HasValue)
{
query = query.Where(x => x.IsBanned == model.IsBanned.Value);
}
if (model.LecturerIds != null)
{
query = query.Where(x => x.LecturerId.HasValue && model.LecturerIds.Contains(x.LecturerId.Value));
}
query = query.OrderBy(x => x.UserName);

View File

@ -20,7 +20,7 @@ namespace SecurityWindowsDesktop
return null;
}
if (!manager.CheckAccess(new SecurityManagerCheckAccessModel(new AccessBindingModel { UserId = UserManager.GetInstance.UserId },
if (!manager.CheckAccess(new SecurityManagerCheckAccessModel(new AccessBindingModel { UserId = manager.User },
AccessOperation.Администрирование, AccessType.SimpleView, "Администрирование")))
{
return null;
@ -40,7 +40,7 @@ namespace SecurityWindowsDesktop
foreach (var cntrl in _controls)
{
if (manager.CheckAccess(new SecurityManagerCheckAccessModel(new AccessBindingModel { UserId = UserManager.GetInstance.UserId },
if (manager.CheckAccess(new SecurityManagerCheckAccessModel(new AccessBindingModel { UserId = manager.User },
cntrl.AccessOperation, AccessType.SimpleView, cntrl.Title)))
{
list.Add(new WindowDesktopExtensionControlModel