diff --git a/DepartmentPortal/Common/DatabaseCore/SecurityManager.cs b/DepartmentPortal/Common/DatabaseCore/SecurityManager.cs
index 8380231..26eaf17 100644
--- a/DepartmentPortal/Common/DatabaseCore/SecurityManager.cs
+++ b/DepartmentPortal/Common/DatabaseCore/SecurityManager.cs
@@ -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() { }
+
+ ///
+ /// Singleton для класса
+ ///
+ public static SecurityManager GetInstance
+ {
+ get
+ {
+ if (_securityManager == null)
+ {
+ lock (_lockObject)
+ {
+ _securityManager = new SecurityManager();
+ }
+ }
+ return _securityManager;
+ }
+ }
+
+ public Guid? User { get; set; }
+
+ public List 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();
+ }
+
+ ///
+ /// Получение хеша пароля
+ ///
+ ///
+ ///
+ private static string GetPasswordHash(string password) => Encoding.ASCII.GetString((new MD5CryptoServiceProvider()).ComputeHash(Encoding.ASCII.GetBytes(password)));
+
+ ///
+ /// Проверка пользователя при авторизации и при смене пароля
+ ///
+ ///
+ ///
+ ///
+ ///
+ 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("Пользователь заблокирован");
+ }
+ }
+ }
}
}
\ No newline at end of file
diff --git a/DepartmentPortal/Common/ModelTools/Interfaces/ISecurityManager.cs b/DepartmentPortal/Common/ModelTools/Interfaces/ISecurityManager.cs
index 60d5726..169e44b 100644
--- a/DepartmentPortal/Common/ModelTools/Interfaces/ISecurityManager.cs
+++ b/DepartmentPortal/Common/ModelTools/Interfaces/ISecurityManager.cs
@@ -1,9 +1,27 @@
using ModelTools.Models;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
namespace ModelTools.Interfaces
{
public interface ISecurityManager
{
+ ///
+ /// Аутентифицированный пользователь
+ ///
+ public Guid? User { get; set; }
+
+ ///
+ /// Список ролей аутентифицированного пользователь
+ ///
+ public List Roles { get; set; }
+
+ ///
+ /// Выполнена ли аутентификация
+ ///
+ public bool IsAuth { get; }
+
///
/// Сообщение с причиной не получения доступа
///
@@ -20,5 +38,27 @@ namespace ModelTools.Interfaces
/// Проверка наличия старотвых данных для работы с ситемой
///
void CheckStartDataSource();
+
+ ///
+ /// Аутентификация пользователя
+ ///
+ ///
+ ///
+ ///
+ Task LoginAsync(string login, string password);
+
+ ///
+ /// Выход из системы
+ ///
+ ///
+ Task LogoutAsync();
+
+ ///
+ /// Смена пароля
+ ///
+ ///
+ ///
+ ///
+ Task ChangePassword(string login, string oldPassword, string newPassword);
}
}
\ No newline at end of file
diff --git a/DepartmentPortal/DepartmentPortalDesctop/DepartmentPortalDesctop.csproj b/DepartmentPortal/DepartmentPortalDesctop/DepartmentPortalDesctop.csproj
index ced7a4a..f35c2cf 100644
--- a/DepartmentPortal/DepartmentPortalDesctop/DepartmentPortalDesctop.csproj
+++ b/DepartmentPortal/DepartmentPortalDesctop/DepartmentPortalDesctop.csproj
@@ -16,7 +16,6 @@
-
diff --git a/DepartmentPortal/DepartmentPortalDesctop/FormEnter.cs b/DepartmentPortal/DepartmentPortalDesctop/FormEnter.cs
index 77a5c01..b81a362 100644
--- a/DepartmentPortal/DepartmentPortalDesctop/FormEnter.cs
+++ b/DepartmentPortal/DepartmentPortalDesctop/FormEnter.cs
@@ -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();
+ Task.WaitAll(Task.Run(async () => await securityManager.LoginAsync(textBoxLogin.Text, textBoxPassword.Text)));
DialogResult = DialogResult.OK;
Close();
}
diff --git a/DepartmentPortal/DepartmentPortalDesctop/Program.cs b/DepartmentPortal/DepartmentPortalDesctop/Program.cs
index 1f9d016..472ce00 100644
--- a/DepartmentPortal/DepartmentPortalDesctop/Program.cs
+++ b/DepartmentPortal/DepartmentPortalDesctop/Program.cs
@@ -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());
}
diff --git a/DepartmentPortal/ImplementationExtensions/net5.0/DatabaseCore.dll b/DepartmentPortal/ImplementationExtensions/net5.0/DatabaseCore.dll
index d5e5315..626cb55 100644
Binary files a/DepartmentPortal/ImplementationExtensions/net5.0/DatabaseCore.dll and b/DepartmentPortal/ImplementationExtensions/net5.0/DatabaseCore.dll differ
diff --git a/DepartmentPortal/ImplementationExtensions/net5.0/ModelTools.dll b/DepartmentPortal/ImplementationExtensions/net5.0/ModelTools.dll
index 78f408e..71032a3 100644
Binary files a/DepartmentPortal/ImplementationExtensions/net5.0/ModelTools.dll and b/DepartmentPortal/ImplementationExtensions/net5.0/ModelTools.dll differ
diff --git a/DepartmentPortal/ImplementationExtensions/net5.0/SecurityBusinessLogic.dll b/DepartmentPortal/ImplementationExtensions/net5.0/SecurityBusinessLogic.dll
index 469e9d4..e13afce 100644
Binary files a/DepartmentPortal/ImplementationExtensions/net5.0/SecurityBusinessLogic.dll and b/DepartmentPortal/ImplementationExtensions/net5.0/SecurityBusinessLogic.dll differ
diff --git a/DepartmentPortal/ImplementationExtensions/net5.0/SecurityImplementation.dll b/DepartmentPortal/ImplementationExtensions/net5.0/SecurityImplementation.dll
index c87212d..9103c80 100644
Binary files a/DepartmentPortal/ImplementationExtensions/net5.0/SecurityImplementation.dll and b/DepartmentPortal/ImplementationExtensions/net5.0/SecurityImplementation.dll differ
diff --git a/DepartmentPortal/Security/SecurityBusinessLogic/BindingModels/UserBindingModels.cs b/DepartmentPortal/Security/SecurityBusinessLogic/BindingModels/UserBindingModels.cs
index daf0b13..41063ef 100644
--- a/DepartmentPortal/Security/SecurityBusinessLogic/BindingModels/UserBindingModels.cs
+++ b/DepartmentPortal/Security/SecurityBusinessLogic/BindingModels/UserBindingModels.cs
@@ -10,13 +10,6 @@ namespace SecurityBusinessLogic.BindingModels
///
public class UserGetBindingModel : GetBindingModel
{
- public bool? IsBanned { get; set; }
-
- public string Login { get; set; }
-
- public string Password { get; set; }
-
- public List LecturerIds { get; set; }
}
///
diff --git a/DepartmentPortal/Security/SecurityBusinessLogic/BusinessLogics/UserManager.cs b/DepartmentPortal/Security/SecurityBusinessLogic/BusinessLogics/UserManager.cs
deleted file mode 100644
index 491c729..0000000
--- a/DepartmentPortal/Security/SecurityBusinessLogic/BusinessLogics/UserManager.cs
+++ /dev/null
@@ -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
-{
- ///
- /// Менеджер по работе с пользователем системы
- ///
- 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();
- _userBusinessLogic = UnityContainerConfigurator.Resolve();
- }
-
- public static UserManager GetInstance
- {
- get
- {
- if (_userManager == null)
- {
- lock (_lockObject)
- {
- _userManager = new UserManager();
- }
- }
-
- return _userManager;
- }
- }
-
- ///
- /// Аутентифицированный пользователь
- ///
- public UserViewModel User { get; private set; }
-
- ///
- /// Список ролей аутентифицированного пользователь
- ///
- public List Roles { get; private set; }
-
- ///
- /// Сообщение об ошибке
- ///
- public string ErrorMessage { get; private set; }
-
- ///
- /// Идентификатор аутентифицированного пользователь
- ///
- public Guid? UserId => User?.Id;
-
- ///
- /// Выполнена ли аутентификация
- ///
- public bool IsAuth => User != null;
-
- ///
- /// Аутентификация пользователя
- ///
- ///
- ///
- ///
- 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();
- });
- }
-
- ///
- /// Выход из системы
- ///
- ///
- public async Task LogoutAsync()
- {
- await Task.Run(() =>
- {
- User = null;
- Roles = null;
- });
- }
-
- ///
- /// Смена пароля
- ///
- ///
- ///
- ///
- 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);
- }
-
- ///
- /// Получение хеша пароля
- ///
- ///
- ///
- public static string GetPasswordHash(string password) => Encoding.ASCII.GetString((new MD5CryptoServiceProvider()).ComputeHash(Encoding.ASCII.GetBytes(password)));
-
- ///
- /// Получение модели для сохранения из представления
- ///
- ///
- ///
- 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
- };
- }
- }
-}
\ No newline at end of file
diff --git a/DepartmentPortal/Security/SecurityImplementation/Implementations/UserService.cs b/DepartmentPortal/Security/SecurityImplementation/Implementations/UserService.cs
index 613e2d9..1ef49a4 100644
--- a/DepartmentPortal/Security/SecurityImplementation/Implementations/UserService.cs
+++ b/DepartmentPortal/Security/SecurityImplementation/Implementations/UserService.cs
@@ -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(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(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(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);
diff --git a/DepartmentPortal/Security/SecurityWindowsDesktop/SecurityWindowDesktopExtension.cs b/DepartmentPortal/Security/SecurityWindowsDesktop/SecurityWindowDesktopExtension.cs
index cf83284..1b58e7e 100644
--- a/DepartmentPortal/Security/SecurityWindowsDesktop/SecurityWindowDesktopExtension.cs
+++ b/DepartmentPortal/Security/SecurityWindowsDesktop/SecurityWindowDesktopExtension.cs
@@ -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
diff --git a/DepartmentPortal/WindowDestopExtensions/net5.0-windows/DesktopTools.dll b/DepartmentPortal/WindowDestopExtensions/net5.0-windows/DesktopTools.dll
index 64a76a6..12937ff 100644
Binary files a/DepartmentPortal/WindowDestopExtensions/net5.0-windows/DesktopTools.dll and b/DepartmentPortal/WindowDestopExtensions/net5.0-windows/DesktopTools.dll differ
diff --git a/DepartmentPortal/WindowDestopExtensions/net5.0-windows/ModelTools.dll b/DepartmentPortal/WindowDestopExtensions/net5.0-windows/ModelTools.dll
index 78f408e..71032a3 100644
Binary files a/DepartmentPortal/WindowDestopExtensions/net5.0-windows/ModelTools.dll and b/DepartmentPortal/WindowDestopExtensions/net5.0-windows/ModelTools.dll differ
diff --git a/DepartmentPortal/WindowDestopExtensions/net5.0-windows/SecurityBusinessLogic.dll b/DepartmentPortal/WindowDestopExtensions/net5.0-windows/SecurityBusinessLogic.dll
index 469e9d4..e13afce 100644
Binary files a/DepartmentPortal/WindowDestopExtensions/net5.0-windows/SecurityBusinessLogic.dll and b/DepartmentPortal/WindowDestopExtensions/net5.0-windows/SecurityBusinessLogic.dll differ
diff --git a/DepartmentPortal/WindowDestopExtensions/net5.0-windows/SecurityWindowsDesktop.dll b/DepartmentPortal/WindowDestopExtensions/net5.0-windows/SecurityWindowsDesktop.dll
index e88a3dd..c68b34d 100644
Binary files a/DepartmentPortal/WindowDestopExtensions/net5.0-windows/SecurityWindowsDesktop.dll and b/DepartmentPortal/WindowDestopExtensions/net5.0-windows/SecurityWindowsDesktop.dll differ