Убрали зависимость Security к десктопному приложению
This commit is contained in:
parent
525add0260
commit
8ad72cd50d
@ -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("Пользователь заблокирован");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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>
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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>());
|
||||
}
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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>
|
||||
|
@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user