2021-03-26 20:09:52 +04:00
|
|
|
|
using DatabaseCore.Models.Security;
|
2021-03-28 19:15:55 +04:00
|
|
|
|
using ModuleTools.Enums;
|
|
|
|
|
using ModuleTools.Interfaces;
|
|
|
|
|
using ModuleTools.Models;
|
2021-03-28 00:15:01 +04:00
|
|
|
|
using System;
|
2021-03-28 10:23:26 +04:00
|
|
|
|
using System.Collections.Generic;
|
2021-03-26 20:09:52 +04:00
|
|
|
|
using System.Linq;
|
2021-03-28 00:15:01 +04:00
|
|
|
|
using System.Security.Cryptography;
|
|
|
|
|
using System.Text;
|
2021-03-28 10:23:26 +04:00
|
|
|
|
using System.Threading.Tasks;
|
2021-03-26 20:09:52 +04:00
|
|
|
|
|
|
|
|
|
namespace DatabaseCore
|
|
|
|
|
{
|
|
|
|
|
public class SecurityManager : ISecurityManager
|
|
|
|
|
{
|
2021-03-28 10:23:26 +04:00
|
|
|
|
private readonly int _countDayToBanned = 3;
|
|
|
|
|
|
|
|
|
|
private readonly int _countMaxAttempt = 3;
|
|
|
|
|
|
|
|
|
|
public Guid? User { get; set; }
|
|
|
|
|
|
|
|
|
|
public List<Guid> Roles { get; set; }
|
|
|
|
|
|
2021-03-26 20:09:52 +04:00
|
|
|
|
public string ErrorMessage { get; set; }
|
|
|
|
|
|
2021-03-28 10:23:26 +04:00
|
|
|
|
public bool IsAuth => User != null;
|
|
|
|
|
|
2021-03-27 23:50:29 +04:00
|
|
|
|
public bool CheckAccess(SecurityManagerCheckAccessModel model)
|
2021-03-26 20:09:52 +04:00
|
|
|
|
{
|
|
|
|
|
using var context = DatabaseManager.GetContext;
|
2021-03-28 10:23:26 +04:00
|
|
|
|
Access access = null;
|
2021-03-28 20:00:42 +04:00
|
|
|
|
if (model.Model != null)
|
2021-03-26 20:09:52 +04:00
|
|
|
|
{
|
|
|
|
|
// если не указан идентификатор пользователя, то смотрим, может он авторизован
|
2021-03-28 10:23:26 +04:00
|
|
|
|
if (!model.Model.UserId.HasValue && User.HasValue)
|
2021-03-26 20:09:52 +04:00
|
|
|
|
{
|
2021-03-28 10:23:26 +04:00
|
|
|
|
model.Model.UserId = User.Value;
|
2021-03-26 20:09:52 +04:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-28 10:52:15 +04:00
|
|
|
|
var roles = context.UserRoles.Where(x => x.UserId == model.Model.UserId && !x.IsDeleted).Select(x => x.Role).OrderByDescending(x => x.RolePriority).ToList();
|
2021-03-26 20:09:52 +04:00
|
|
|
|
if (roles == null)
|
|
|
|
|
{
|
|
|
|
|
ErrorMessage = $"Не верный пользователь";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2021-03-27 23:50:29 +04:00
|
|
|
|
access = context.Accesses.FirstOrDefault(a => a.AccessOperation == model.Operation && roles.Contains(a.Role));
|
2021-03-26 20:09:52 +04:00
|
|
|
|
}
|
2021-03-28 10:23:26 +04:00
|
|
|
|
else if (Roles != null)
|
2021-03-26 20:09:52 +04:00
|
|
|
|
{
|
2021-03-28 10:23:26 +04:00
|
|
|
|
access = context.Accesses.FirstOrDefault(a => a.AccessOperation == model.Operation && Roles.Contains(a.RoleId));
|
2021-03-26 20:09:52 +04:00
|
|
|
|
}
|
|
|
|
|
if (access != null)
|
|
|
|
|
{
|
2021-03-27 23:50:29 +04:00
|
|
|
|
if (access.AccessType >= model.Type) return true;
|
2021-03-26 20:09:52 +04:00
|
|
|
|
}
|
2021-03-27 23:50:29 +04:00
|
|
|
|
switch (model.Type)
|
2021-03-26 20:09:52 +04:00
|
|
|
|
{
|
2021-03-28 19:58:42 +04:00
|
|
|
|
case AccessType.View:
|
2021-03-27 23:50:29 +04:00
|
|
|
|
ErrorMessage = $"Нет доступа на чтение данных по сущности '{model.Entity}'";
|
2021-03-26 20:09:52 +04:00
|
|
|
|
return false;
|
|
|
|
|
case AccessType.Change:
|
2021-03-27 23:50:29 +04:00
|
|
|
|
ErrorMessage = $"Нет доступа на изменение данных по сущности '{model.Entity}'";
|
2021-03-26 20:09:52 +04:00
|
|
|
|
return false;
|
|
|
|
|
case AccessType.Delete:
|
2021-03-27 23:50:29 +04:00
|
|
|
|
ErrorMessage = $"Нет доступа на удаление данных по сущности '{model.Entity}'";
|
2021-03-26 20:09:52 +04:00
|
|
|
|
return false;
|
|
|
|
|
default:
|
2021-03-27 23:50:29 +04:00
|
|
|
|
ErrorMessage = $"Нет доступа по сущности '{model.Entity}'";
|
2021-03-26 20:09:52 +04:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-28 00:15:01 +04:00
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
transaction.Commit();
|
|
|
|
|
}
|
2021-03-28 10:23:26 +04:00
|
|
|
|
|
|
|
|
|
public async Task LoginAsync(string login, string password)
|
|
|
|
|
{
|
|
|
|
|
var passwordHash = GetPasswordHash(password);
|
|
|
|
|
using var context = DatabaseManager.GetContext;
|
2021-03-28 10:52:40 +04:00
|
|
|
|
var user = context.Users.FirstOrDefault(x => x.UserName == login && x.PasswordHash == passwordHash && !x.IsDeleted);
|
2021-03-28 10:23:26 +04:00
|
|
|
|
await CheckUserAsync(login, user, context);
|
|
|
|
|
user.DateLastVisit = DateTime.Now;
|
|
|
|
|
user.CountAttempt = 0;
|
|
|
|
|
await context.SaveChangesAsync();
|
|
|
|
|
|
|
|
|
|
User = user.Id;
|
2021-03-28 10:52:40 +04:00
|
|
|
|
Roles = context.UserRoles.Where(x => x.UserId == user.Id && !x.IsDeleted).Select(x => x.RoleId).ToList();
|
2021-03-28 10:23:26 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
2021-03-28 10:52:40 +04:00
|
|
|
|
var user = context.Users.FirstOrDefault(x => x.UserName == login && x.PasswordHash == GetPasswordHash(oldPassword) && !x.IsDeleted);
|
2021-03-28 10:23:26 +04:00
|
|
|
|
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)
|
|
|
|
|
{
|
2021-03-28 10:52:40 +04:00
|
|
|
|
user = context.Users.FirstOrDefault(x => x.UserName == login && !x.IsDeleted);
|
2021-03-28 10:23:26 +04:00
|
|
|
|
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("Пользователь заблокирован");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-26 20:09:52 +04:00
|
|
|
|
}
|
|
|
|
|
}
|