DepartmentProject/DepartmentPortal/Common/CoreDatabase/SecurityManager.cs

235 lines
7.0 KiB
C#
Raw Normal View History

2022-03-18 22:55:48 +04:00
using CoreDatabase.Models.Security;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
2022-03-20 10:10:44 +04:00
using ToolsModule.ManagmentSecurity;
2022-03-18 22:55:48 +04:00
namespace CoreDatabase
{
public class SecurityManager : ISecurityManager
{
private readonly int _countDayToBanned = 3;
private readonly int _countMaxAttempt = 3;
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 = null;
if (model.Model != null)
{
// если не указан идентификатор пользователя, то смотрим, может он авторизован
if (!model.Model.UserIdForAccess.HasValue && User.HasValue)
{
model.Model.UserIdForAccess = User.Value;
}
var roles = context.UserRoles.Where(x => x.UserId == model.Model.UserIdForAccess && !x.IsDeleted).Select(x => x.Role).OrderByDescending(x => x.RolePriority).ToList();
if (roles == null)
{
ErrorMessage = $"Не верный пользователь";
return false;
}
access = context.Accesses.FirstOrDefault(a => a.AccessOperation == model.Operation && roles.Contains(a.Role));
}
else if (Roles != null)
{
access = context.Accesses.FirstOrDefault(a => a.AccessOperation == model.Operation && Roles.Contains(a.RoleId));
}
if (access != null)
{
if (access.AccessType >= model.Type) return true;
}
switch (model.Type)
{
case AccessType.View:
ErrorMessage = $"Нет доступа на чтение данных по сущности '{model.Entity}'";
return false;
case AccessType.Change:
ErrorMessage = $"Нет доступа на изменение данных по сущности '{model.Entity}'";
return false;
case AccessType.Delete:
ErrorMessage = $"Нет доступа на удаление данных по сущности '{model.Entity}'";
return false;
default:
ErrorMessage = $"Нет доступа по сущности '{model.Entity}'";
return false;
}
}
public void CheckStartDataSource()
{
using var context = DatabaseManager.GetContext;
using var transaction = context.Database.BeginTransaction();
var role = context.Roles.FirstOrDefault(x => x.RoleName == "Администратор");
if (role == null)
{
role = new Role
{
RoleName = "Администратор",
RolePriority = 100
};
context.Roles.Add(role);
context.SaveChanges();
}
var accesses = context.Accesses.Where(x => x.RoleId == role.Id);
foreach (AccessOperation operation in Enum.GetValues(typeof(AccessOperation)))
{
if (!accesses.Any(x => x.AccessOperation == operation && x.AccessType == AccessType.Delete))
{
context.Accesses.Add(new Access
{
AccessOperation = operation,
AccessType = AccessType.Delete,
RoleId = role.Id
});
}
}
context.SaveChanges();
var md5 = new MD5CryptoServiceProvider();
var user = context.Users.FirstOrDefault(x => x.UserName == "admin");
if (user == null)
{
user = new User
{
UserName = "admin",
PasswordHash = Encoding.ASCII.GetString(md5.ComputeHash(Encoding.ASCII.GetBytes("qwerty"))),
CountAttempt = 0
};
context.Users.Add(user);
context.SaveChanges();
}
var link = context.UserRoles.FirstOrDefault(x => x.RoleId == role.Id && x.UserId == user.Id);
if (link == null)
{
context.UserRoles.Add(new UserRole
{
RoleId = role.Id,
UserId = user.Id
});
context.SaveChanges();
}
List<string> enviromentKeys = new()
{
"Практика",
"Учебный год",
"Даты семестра",
"Дисциплины (модули)",
"Кафедра",
"ГИА",
"SyncStudentOrderIpAddress",
"SyncStudentOrderUserName",
"SyncStudentOrderPassword"
};
foreach(var key in enviromentKeys)
{
var es = context.EnviromentSettings.FirstOrDefault(x => x.Key == key);
if(es == null)
{
context.EnviromentSettings.Add(new EnviromentSetting
{
Key = key,
Value = "Прописать значение!"
});
}
}
context.SaveChanges();
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 && !x.IsDeleted);
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 && !x.IsDeleted).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) && !x.IsDeleted);
await CheckUserAsync(login, user, context);
user.PasswordHash = GetPasswordHash(newPassword);
await context.SaveChangesAsync();
}
/// <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="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 && !x.IsDeleted);
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("Пользователь заблокирован");
}
}
}
}
}