Очень часто в работе сталкиваюсь с проблемой разделения прав доступа к разделам сайта и элементам управления.
Сначала мне хватало инструментов, которые предоставляет ASP MVC «из коробки», но, со временем, я столкнулся с необходимостью создания своего инструмента разделения прав. Если тебе, уважаемый читатель, интересно как можно решить эту проблему, добро пожаловать под кат.
Немного лирики
В одном из проектов столкнулся с проблемой разделения прав доступа к разделам и элементам сайта. Это внутренний сайт компании на котором сотрудники могут планировать свой отпуск. ТЗ было написано, на удивление, хорошо. Работа шла ударными темпами и уже через месяц работы был готов рабочий прототип. Все были в восторге ровно до того момента, как не начались «уточнения» по работе системы. А так как бюрократ сидит в нашем человеке с рождения, была куча согласований и обсуждений, результатом которых было что-то вроде такого: «Все отлично. Но вот это не должен видеть обычный пользователь. А это должен видеть только администратор. А это должен видеть только особо секретный администратор и никто другой!». И это, к сожалению, не конец бурной фантазии заказчика.
Стандартными средствами управление ролями и доступами сделать можно, но очень уж муторно. Поэтому я взялся за создание модуля разделения прав доступа, которым можно легко управлять.
Приступая к работе
Для начала были выведены основные требования к модулю.
- Простое разделение прав доступа к методам контроллеров (по принципу работы аттрибута Authorize)
- Простой в работе механизм разделения доступа к элементам сайта
- Возможность создавать роли с любыми вариациями доступа
- Возможность использования в разных проектах
Потом была проведена «работа» по рисованию различных схем и просмотра огромной кучи материалов по теме. В итоге была выработана концепция модуля.
Данные, необходимые для работы модуля, будут храниться в базе MSSQL (а на чем же еще, если пишем на c#). Централизованное хранилище делать не стал из-за особенностей структуры корпоративной сети и идеи использования (в теории) на любом проекте. Поэтому будем писать в базы проектов свой набор данных модуля.
Также исходя из идеи, что модуль должен работать с любым проектом, он должен читать настройки из файла web.config проекта, к которому подключен модуль.
Ну и пусть модуль умеет подготавливать для себя базу и делает начальную конфигурацию, чтобы развертывание на новом проекте было простым как… кхм. Ну вы поняли.
И на вкусное, пусть он по умолчанию заносит все вновь созданные или добавленные элементы и разделы в таблицы и дает доступ «суперадмину», чтобы при работы не пришлось каждый раз лезть в настройки.
Начало работы
Для начала хочу сказать пару слов о получившемся модуле. Для своей работы он использует самописный RoleProvider. И причиной его использования опять же стали особенности корпоративной сети. Таким образом на одном из серверов сделан справочник в котором находятся все данные по сотрудниками и привязка к доменному логину. Не спрашивайте почему. Это устоявшееся положение вещей.
Так вот, для внутренних нужд в справочнике есть группы для сотрудников. Поэтому был написан свой провайдер ролей, который не только выполнял свои основные функции, но оперировал группами в справочнике на сервере. Его приводить я не буду, так как особого интереса он не представляет и ничего нового в написании провайдера вы не найдете. (в фрагментах кода будет встречаться обращение к пространству имен AuthLib, которое и содержит провайдер ролей).
Пока не пошел код, я хочу попросить прощения за комментарии и другой мусор в коде. Приведенный код является устаревшим(в реалиях текущих проектов) и приведен только для демонстрации идеи.
Первым делом создаем класс, описывающий пользователя. Так будет проще работать в будущем.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.SqlClient;
namespace Ekzo.BaseClasses
{
public class Employee : IEquatable<Employee>
{
/// <summary>
/// Идентификатор сотрудника по БД
/// </summary>
public int Id { get; set; }
/// <summary>
/// ФИО сотрудника
/// </summary>
public string Name { get; set; }
/// <summary>
/// Конструктор класса
/// </summary>
/// <param name="id">Идентификатор из БД</param>
public Employee(int id)
{
InitClass(id);
}
/// <summary>
/// Конструктор класса
/// </summary>
/// <param name="employeeName">ФИО сотрудника</param>
public Employee(string employeeName)
{
using (SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Ekzo.Web.Configuration.StringName].ConnectionString))
{
using (SqlCommand cmd = new SqlCommand("SELECT employee_id FROM employee WHERE employee_name LIKE @employeeName+'%' AND date_fired IS NULL", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@employeeName", string.Join("%", employeeName.Split(char.Parse(" "))));
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
this.Id = reader.GetInt32(0);
}
reader.Close();
}
catch (Exception ex)
{
if (Ekzo.Web.Configuration.s_log != null)
Ekzo.Web.Configuration.s_log.Error("[Ошибка модуля авторизации] [Ошибка создания класса пользователя]", ex);
}
}
}
if (this.Id != 0)
InitClass(this.Id);
}
/// <summary>
/// Конструктор класса
/// </summary>
public Employee() { }
/// <summary>
/// Инициализация полей класса
/// </summary>
/// <param name="id">Идентификатор сотрудника по БД</param>
private void InitClass(int id)
{
this.Id = id;
using (SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Ekzo.Web.Configuration.StringName].ConnectionString))
{
using (SqlCommand cmd = new SqlCommand("SELECT employee_name FROM employee WHERE employee_id=@employeeID AND date_fired IS NULL", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@employeeID", this.Id);
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
this.Name = reader.GetString(0);
}
reader.Close();
}
catch (Exception ex)
{
if (Ekzo.Web.Configuration.s_log != null)
Ekzo.Web.Configuration.s_log.Error("[Ошибка модуля авторизации] [Ошибка инициализации класса пользователя]", ex);
}
}
}
}
public bool Equals(Employee x, Employee y)
{
if (x.Name == y.Name && x.Id == y.Id)
return true;
else
return false;
}
public override int GetHashCode()
{
int hasEmployeeName = this.Name == null ? 0 : this.Name.GetHashCode();
int hasID = this.Id == 0 ? 0 : this.Id.GetHashCode();
return hasEmployeeName ^ hasID;
}
public bool Equals(Employee other)
{
if (this.Name == other.Name && this.Id == other.Id)
return true;
else
return false;
}
bool IEquatable<Employee>.Equals(Employee other)
{
if (this.Name == other.Name && this.Id == other.Id)
return true;
else
return false;
}
}
}
Теперь подготовим классы, описывающие элементы системы (разделы, ссылки, элементы управления и т.д.)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
namespace Ekzo.Web.Security.Utilization.Authorization
{
/// <summary>
/// Класс описывающий метод. Используется для определения соответствий имени действия и роли, имеющей доступ к нему.
/// </summary>
public class Action
{
/// <summary>
/// Идентификатор по БД
/// </summary>
public int id { get; private set; }
/// <summary>
/// Группы, к которым относится метод
/// </summary>
private int[] _ActionGroups;
/// <summary>
/// Группы, к которым относится метод
/// </summary>
public ActionGroup[] ActionGroups
{
get
{
List<ActionGroup> Groups = new List<ActionGroup>();
if (_ActionGroups != null)
{
for (int i = 0; i < _ActionGroups.Count(); i++)
Groups.Add(new ActionGroup(_ActionGroups[i]));
return Groups.ToArray();
}
return null;
}
}
/// <summary>
/// Имя метода в системе разграничения достука
/// </summary>
public string ActionName { get; set; }
/// <summary>
/// Флаг индикатор активности правила
/// </summary>
public bool Active { get; private set; }
#region ClassBuilder
public Action() { }
public Action(string ActionName)
{
InitClass(ActionName);
}
public Action(int id)
{
InitClass(null, id);
}
private void InitClass(string name, int id = 0, int actionGroup = 0)
{
if (id != 0) this.id = id;
if (!string.IsNullOrEmpty(name)) this.ActionName = name;
//this._ActionGroups = actionGroup;
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("SELECT * FROM Authorization_Actions WHERE id=@id OR Name=@actionName", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@id", id);
cmd.Parameters.AddWithValue("@actionName", string.IsNullOrEmpty(name) ? "" : name);
System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
this.id = reader.GetInt32(0);
this.ActionName = reader.GetString(1);
this.Active = reader.GetBoolean(2);
}
reader.Close();
List<int> actionGroups = new List<int>();
cmd.CommandText = "SELECT GroupID FROM Authorization_ActionToGroup WHERE ActionID=@id";
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("@id", this.id);
reader = cmd.ExecuteReader();
while (reader.Read())
actionGroups.Add(reader.GetInt32(0));
this._ActionGroups = actionGroups.ToArray();
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Инициализация класса действия] ", ex);
}
}
}
}
#endregion
/// <summary>
/// Сохранение метода
/// </summary>
public void Save()
{
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(@"
IF((SELECT COUNT(*) FROM Authorization_Actions WHERE id=@id OR Name=@name)=0)
BEGIN
INSERT INTO Authorization_Actions(Name) VALUES(@name)
INSERT INTO Authorization_ActionToGroup(ActionID,GroupID) VALUES((SELECT TOP(1) id FROM Authorization_Actions WHERE Name=@name),0)
END
ELSE
UPDATE Authorization_Actions SET Name=@name, Active=@active
SELECT * FROM Authorization_Actions WHERE Name=@name", conn))
{
try
{
conn.Open();
if (!string.IsNullOrEmpty(this.ActionName) && this.id == 0) cmd.CommandText = cmd.CommandText.Replace("WHERE id=@id OR Name=@name", "WHERE Name=@name");
cmd.Parameters.AddWithValue("@id", this.id);
cmd.Parameters.AddWithValue("@name", this.ActionName);
cmd.Parameters.AddWithValue("@active", this.Active);
//cmd.Parameters.AddWithValue("@groupID", this._ActionGroup);
System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
List<int> actionGroups = new List<int>();
while (reader.Read())
{
this.id = reader.GetInt32(0);
this.ActionName = reader.GetString(1);
this.Active = reader.GetBoolean(2);
}
reader.Close();
cmd.CommandText = "SELECT GroupID FROM Authorization_ActionToGroup WHERE ActionID=@id";
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("@id", this.id);
reader = cmd.ExecuteReader();
while (reader.Read())
actionGroups.Add(reader.GetInt32(0));
this._ActionGroups = actionGroups.ToArray();
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Сохранение действия в БД] ", ex);
}
}
}
}
/// <summary>
/// Удаление метода
/// </summary>
public void Delete()
{
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("DELETE FROM Authorization_Actions WHERE id=@id", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@id", this.id);
cmd.ExecuteNonQuery();
cmd.CommandText = "DELETE FROM Autorization_ActionToGroup WHERE ActionID=@id";
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Удаление действия из БД] ", ex);
}
}
}
}
/// <summary>
/// Проверка на существование метода
/// </summary>
/// <returns></returns>
public bool IsExist()
{
return IsExist(this.ActionName);
}
/// <summary>
/// Проверка существования метода
/// </summary>
/// <param name="ActionName">Имя метода</param>
/// <returns></returns>
public static bool IsExist(string ActionName)
{
bool result = false;
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("SELECT COUNT(*) FROM Authorization_Actions WHERE Name=@name", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@name", ActionName);
System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
result = reader.GetInt32(0) == 0 ? false : true;
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Проверка существования действия в БД] ", ex);
}
}
}
return result;
}
/// <summary>
/// Получение списка всех доступных методов
/// </summary>
/// <returns></returns>
public static List<Action> GetAllActions()
{
List<Action> result = new List<Action>();
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("SELECT id FROM Authorization_Actions ORDER BY Name ", conn))
{
try
{
conn.Open();
System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
result.Add(new Action(reader.GetInt32(0)));
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Получение всех действий] ", ex);
}
}
}
return result;
}
/// <summary>
/// Добавление метода в группу
/// </summary>
/// <param name="groupID"></param>
public void AddToGroup(int groupID)
{
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(@"
IF((SELECT COUNT(*) FROM Authorization_ActionToGroup WHERE ActionID=@action AND GroupID=@group)=0)
INSERT INTO Authorization_ActionToGroup(ActionID,GroupID) VALUES(@action,@group)", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@action", groupID);
cmd.Parameters.AddWithValue("@group", this.id);
cmd.ExecuteNonQuery();
new Action(this.id);
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Добавление действия в группу] ", ex);
}
}
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Ekzo.Web.Security.Utilization.Authorization
{
/// <summary>
/// Класс описывает группы методов
/// </summary>
public class ActionGroup
{
/// <summary>
/// Идентификатор группы в БД
/// </summary>
public int id { get; private set; }
/// <summary>
/// Список ролей, которым разрешен доступ к группе
/// </summary>
public SystemRole[] Roles { get; private set; }
/// <summary>
/// Название группы
/// </summary>
public string Name { get; private set; }
/// <summary>
/// Идентификатор активности группы. Если группа не активны, правила перестают работать.
/// </summary>
public bool Active { get; set; }
/// <summary>
/// Методы группы.
/// </summary>
public Action[] GroupActions { get; private set; }
#region ClassBuilder
public ActionGroup(int id)
{
InitClass(null, id);
}
public ActionGroup(string name) { InitClass(name); }
private void InitClass(string name, int id = 0)
{
if (id != 0) this.id = id;
if (!string.IsNullOrEmpty(name)) this.Name = name;
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("SELECT * FROM Authorization_ActionGroups WHERE id=@id OR Name=@groupName", conn))
{
try
{
conn.Open();
if (!string.IsNullOrEmpty(name) && id == 0) cmd.CommandText = "SELECT * FROM Authorization_ActionGroups WHERE Name=@groupName";
cmd.Parameters.AddWithValue("@id", this.id);
cmd.Parameters.AddWithValue("@groupName", this.Name == null ? "" : this.Name);
System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
this.id = reader.GetInt32(0);
if (string.IsNullOrEmpty(this.Name)) this.Name = reader.GetString(1);
this.Active = reader.GetBoolean(2);
}
reader.Close();
cmd.CommandText = "SELECT * FROM Authorization_RoleToActionGroup WHERE ActionGroup=@groupID";
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("@groupID", this.id);
reader = cmd.ExecuteReader();
List<SystemRole> rolesList = new List<SystemRole>();
while (reader.Read())
rolesList.Add(new SystemRole(this.id, reader.GetString(2)));
this.Roles = rolesList.ToArray();
reader.Close();
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("@id", this.id);
List<Action> actionsList = new List<Action>();
cmd.CommandText = "SELECT ActionID FROM Authorization_ActionToGroup WHERE GroupID=@id";
reader = cmd.ExecuteReader();
while (reader.Read())
{
actionsList.Add(new Action(reader.GetInt32(0)));
}
this.GroupActions = actionsList.Distinct().ToArray();
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Инициализация класса действия] ", ex);
}
}
}
}
#endregion
/// <summary>
/// Сохранение группы
/// </summary>
public void Save()
{
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(@"
IF((SELECT COUNT(*) FROM Authorization_ActionGroups WHERE Name=@name)=0)
INSERT INTO Authorization_ActionGroups(Name) VALUES(@name)
ELSE
UPDATE Authorization_ActionGroups SET Name=@name, Active=@active WHERE id=@id
SELECT * FROM Authorization_ActionGroups WHERE Name=@name", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@id", this.id);
cmd.Parameters.AddWithValue("@name", this.Name);
cmd.Parameters.AddWithValue("@active", this.Active);
System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
this.id = reader.GetInt32(0);
this.Name = reader.GetString(1);
this.Active = reader.GetBoolean(2);
}
reader.Close();
cmd.CommandText = "SELECT * FROM Authorization_RoleToActionGroup WHERE ActionGroup=@id";
reader = cmd.ExecuteReader();
List<SystemRole> rolesList = new List<SystemRole>();
while (reader.Read())
rolesList.Add(new SystemRole(reader.GetString(2)));
this.Roles = rolesList.ToArray();
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Сохранение группы действий] ", ex);
}
}
}
}
/// <summary>
/// Удаление группы.
/// </summary>
/// <remarks>При удалении группы также выполняется удаление всех связанных элементов.</remarks>
public void Delete()
{
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("DELETE FROM Authorization_ActionGroups WHERE id=@id", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@id", this.id);
cmd.ExecuteNonQuery();
cmd.CommandText = "DELETE FROM Authorization_RoleToActionGroup WHERE ActionGroup=@id";
cmd.ExecuteNonQuery();
cmd.CommandText = "DELETE FROM Authorization_ActionToGroup WHERE GroupID=@id";
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Удаление группы действий] ", ex);
}
}
}
}
/// <summary>
/// Удаление метода из группы
/// </summary>
/// <param name="actionID">Идентификатор метода</param>
public void DeleteAction(int actionID)
{
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("DELETE FROM Authorization_ActionToGroup WHERE ActionID=@action AND GroupID=@group", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@action", actionID);
cmd.Parameters.AddWithValue("@group", this.id);
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Удаление действия из группы] ", ex);
}
}
}
}
/// <summary>
/// Удаление роли из группы
/// </summary>
/// <param name="roleID">Идентификатор роли</param>
public void DeleteRole(int roleID)
{
string roleName = "";
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Ekzo.Web.Configuration.StringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("SELECT group_name FROM groups WHERE group_id=@id", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@id", roleID);
System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
roleName = reader.GetString(0);
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Удаление роли из справочника] ", ex);
}
}
}
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("DELETE FROM Authorization_RoleToActionGroup WHERE ActionGroup=@group AND Role=@roleName", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@roleName", roleName);
cmd.Parameters.AddWithValue("@group", this.id);
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Удаление роли из группы действий] ", ex);
}
}
}
}
/// <summary>
/// Получение списка всех групп
/// </summary>
/// <returns></returns>
public static List<ActionGroup> GetAllgroups()
{
List<ActionGroup> result = new List<ActionGroup>();
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("SELECT id FROM Authorization_ActionGroups", conn))
{
try
{
conn.Open();
System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
result.Add(new ActionGroup(reader.GetInt32(0)));
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Получение списка групп действий] ", ex);
}
}
}
return result;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Ekzo.Web.Security.Utilization.Authorization
{
/// <summary>
/// Класс описывает контролы, которые имеют разграничение доступа
/// </summary>
public class PageControl
{
/// <summary>
/// Идентификатор контрола по БД разграничения прав
/// </summary>
public int id { get; private set; }
/// <summary>
/// Название контрола в БД
/// </summary>
public string Name { get; set; }
/// <summary>
/// Группы, к которым привязан контрол
/// </summary>
public List<PageControlsGroup> Groups { get; set; }
#region ClassBuilder
public PageControl(int id)
{
InitClass(id, null);
}
public PageControl(string name)
{
InitClass(0, name);
}
private void InitClass(int id, string Name)
{
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
//Если контрол еще не занесен в БД, добавляем его в список
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(@"IF((SELECT COUNT(*) FROM Authorization_Controls WHERE Name=@name OR id=@id)=0)
INSERT INTO Authorization_Controls(Name) VALUES (@name)", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@name", Name == null ? "" : Name);
cmd.Parameters.AddWithValue("@id", id);
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT id,Name FROM Authorization_Controls WHERE Name=@name OR id=@id";
System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
this.id = reader.GetInt32(0);
this.Name = reader.GetString(1);
}
reader.Close();
//Если контрол еще не добавлен в группу контролов суперадмина, добавляем
//Группа суперадмина -1
cmd.CommandText = "IF((SELECT COUNT(*) FROM Authorization_ControlToGroup WHERE ControlID=@id AND GroupID=-1)=0) INSERT INTO Authorization_ControlToGroup(ControlID,GroupID) VALUES(@id,-1)";
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("@id", this.id);
cmd.Parameters.AddWithValue("@name", this.Name);
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Инициализация класса элемента управления] ", ex);
}
}
}
this.Groups = new List<PageControlsGroup>();
List<int> groupsIDs = new List<int>();
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("SELECT GroupID FROM Authorization_ControlToGroup WHERE ControlID=@id", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@id", this.id);
System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
groupsIDs.Add(reader.GetInt32(0));
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Инициализация класса элемента управления] ", ex);
}
}
}
for (int i = 0; i < groupsIDs.Count; i++)
this.Groups.Add(new PageControlsGroup(groupsIDs[i]));
}
#endregion
/// <summary>
/// Добавление контрола в группу
/// </summary>
/// <param name="groupID"></param>
public void AddToGroup(int groupID)
{
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(@"IF((SELECT COUNT(*) FROM Authorization_ControlToGroup WHERE ControlID=@id AND GroupID=@group)=0)
INSERT INTO Authorization_ControlToGroup(ControlID,GroupID) VALUES(@id,@group)", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@id", this.id);
cmd.Parameters.AddWithValue("@group", groupID);
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Добавление элемента управления в группу] ", ex);
}
}
}
}
/// <summary>
/// Сохранение контрола
/// </summary>
public void Save()
{
string commandText = this.id == 0 ? "INSERT INTO Authorization_Controls (Name) VALUES(@name)" : "UPDATE Authorization_Controls SET Name=@name WHERE id=@id";
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(commandText, conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@name", this.Name);
cmd.Parameters.AddWithValue("@id", this.id);
cmd.ExecuteNonQuery();
cmd.CommandText = "IF((SELECT COUNT(*) FROM Authorization_ControlToGroup WHERE ControlID=(SELECT TOP(1) id FROM Authorization_Controls WHERE Name=@name) AND GroupID=-1)=0) INSERT INTO Authorization_ControlToGroup(ControlID,GroupID) VALUES(SELECT TOP(1) id FROM Authorization_Controls WHERE Name=@name,-1)";
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Сохранение элемента управления] ", ex);
}
}
}
}
/// <summary>
/// Удаление контрола
/// </summary>
public void Delete()
{
if (this.id == 0) return;
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("DELETE FROM Authorization_Controls WHERE id=@id", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@id", this.id);
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Удаление элемента управления] ", ex);
}
}
}
}
/// <summary>
/// Получение списка всех контролов
/// </summary>
/// <returns></returns>
public static PageControl[] GetAllControls()
{
List<PageControl> result = new List<PageControl>();
List<int> controlsIDs = new List<int>();
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("SELECT id FROM Authorization_Controls ORDER BY Name", conn))
{
try
{
conn.Open();
System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
controlsIDs.Add(reader.GetInt32(0));
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Получение списка элементов управления] ", ex);
}
}
}
for (int i = 0; i < controlsIDs.Count; i++)
result.Add(new PageControl(controlsIDs[i]));
return result.ToArray();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Ekzo.Web.Security.Utilization.Authorization
{
/// <summary>
/// Класс описывает группу контролов
/// </summary>
public class PageControlsGroup : IEquatable<PageControlsGroup>, IEqualityComparer<PageControlsGroup>
{
/// <summary>
/// Идентификатор группы по БД разграничения правд
/// </summary>
public int id { get; private set; }
/// <summary>
/// Имя группы
/// </summary>
public string Name { get; set; }
/// <summary>
/// Список ролей, принадлежащих группе
/// </summary>
public List<ControlsGroupRole> Roles { get; set; }
#region ClassBuilder
public PageControlsGroup(int id)
{
InitClass(id, "");
}
public PageControlsGroup(string Name)
{
this.Name = Name;
InitClass(0, Name);
}
public PageControlsGroup(int id, string Name)
{
this.id = id;
this.Name = Name;
this.Roles = new PageControlsGroup(id).Roles;
}
private void InitClass(int id, string name)
{
//this.Controls = new List<PageControl>();
this.Roles = new List<ControlsGroupRole>();
List<int> pageControls = new List<int>();
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("SELECT * FROM Authorization_ControlsGroup WHERE id=@id OR Name=@name", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@id", id);
cmd.Parameters.AddWithValue("@name", name);
System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
this.id = reader.GetInt32(0);
this.Name = reader.GetString(1);
}
reader.Close();
cmd.CommandText = @"SELECT Authorization_Controls.id AS ControlID
FROM Authorization_ControlToGroup INNER JOIN
Authorization_ControlsGroup ON Authorization_ControlToGroup.GroupID = Authorization_ControlsGroup.id INNER JOIN
Authorization_Controls ON Authorization_ControlToGroup.ControlID = Authorization_Controls.id
WHERE Authorization_ControlsGroup.id=@id OR Authorization_ControlsGroup.Name=@name";
reader = cmd.ExecuteReader();
while (reader.Read())
pageControls.Add(reader.GetInt32(0));
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Инициализация класса группы элементов управления] ", ex);
}
}
}
//for(int i=0;i<pageControls.Count;i++)
// this.Controls.Add(new PageControl(pageControls[i]));
List<int> groupRoles = new List<int>();
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("SELECT RoleID FROM Authorization_RoleToControlGroup WHERE GroupID=@id", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@id", this.id);
System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
groupRoles.Add(reader.GetInt32(0));
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Получение списка ролей группы элементов управления] ", ex);
}
}
}
for (int i = 0; i < groupRoles.Count; i++)
this.Roles.Add(new ControlsGroupRole(groupRoles[i], this.id));
}
#endregion
/// <summary>
/// Получени списка всех групп
/// </summary>
/// <returns></returns>
public static PageControlsGroup[] GetAllGroups()
{
List<PageControlsGroup> result = new List<PageControlsGroup>();
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("SELECT * FROM Authorization_ControlsGroup", conn))
{
try
{
conn.Open();
System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
result.Add(new PageControlsGroup(reader.GetInt32(0), reader.GetString(1)));
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Получение списка групп элементов управления] ", ex);
}
}
}
return result.ToArray();
}
/// <summary>
/// Сохранение группы
/// </summary>
public void Save()
{
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("IF((SELECT COUNT(*) FROM Authorization_ControlsGroup WHERE Name=@name)=0) INSERT INTO Authorization_ControlsGroup(Name) VALUES(@name)", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@name", this.Name);
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Сохранение группы элементов управления] ", ex);
}
}
}
PageControlsGroup newGroup = new PageControlsGroup(this.Name);
this.id = newGroup.id;
this.Roles = newGroup.Roles;
newGroup = null;
}
/// <summary>
/// Удаление группы
/// </summary>
public void Delete()
{
if (this.id != 0)
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("DELETE FROM Authorization_ControlsGroup WHERE id=@id", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@id", this.id);
cmd.ExecuteNonQuery();
cmd.CommandText = "DELETE FROM Authorization_RoleToControlGroup WHERE GroupID=@id";
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Удаление группы элементов управления] ", ex);
}
}
}
}
/// <summary>
/// Удаление контрола из группы
/// </summary>
/// <param name="controlID">Идентификатор контрола</param>
public void DeleteControl(int controlID)
{
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("DELETE FROM Authorization_ControlToGroup WHERE ControlID=@control AND GroupID=@id", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@control", controlID);
cmd.Parameters.AddWithValue("@id", this.id);
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Удаление элемента управления] ", ex);
}
}
}
}
/// <summary>
/// Удаление роли
/// </summary>
/// <param name="roleID">Идентификатор роли</param>
public void DeleteRole(int roleID)
{
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("DELETE FROM Authorization_RoleToControlGroup WHERE RoleID=@role AND GroupID=@id", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@id", this.id);
cmd.Parameters.AddWithValue("@role", roleID);
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Удаление роли элемента управления] ", ex);
}
}
}
}
#region InterfaceImplementation
bool IEquatable<PageControlsGroup>.Equals(PageControlsGroup other)
{
return this.id == other.id & this.Name == other.Name;
}
public bool Equals(PageControlsGroup x, PageControlsGroup y)
{
return x.id == y.id & x.Name == y.Name;
}
public int GetHashCode(PageControlsGroup obj)
{
return this.id.GetHashCode() + this.Name.GetHashCode() + this.Roles.GetHashCode();
}
#endregion
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Ekzo.Web.Security.Utilization.Authorization
{
/// <summary>
/// Класс описывает привязку ролей к группе контролов
/// </summary>
public class ControlsGroupRole
{
/// <summary>
/// Идентификатор роли по БД ConsUser
/// </summary>
public int id { get; private set; }
/// <summary>
/// Имя роли
/// </summary>
public string Role
{
get
{
string result = null;
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Ekzo.Web.Configuration.StringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("SELECT group_name FROM groups WHERE group_id=@id", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@id", this.RoleID);
System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
result = reader.GetString(0);
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Получение названия группы для роли] ", ex);
}
}
}
return result;
}
}
/// <summary>
/// Идентификатор роли
/// </summary>
public int RoleID { get; set; }
/// <summary>
/// Идентификатор группы
/// </summary>
public int GroupID { get; set; }
public ControlsGroupRole(int id, int groupID)
{
this.id = id;
this.GroupID = groupID;
InitClass(id, groupID);
}
private void InitClass(int id, int groupID)
{
this.RoleID = id;
this.GroupID = groupID;
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("SELECT * FROM Authorization_RoleToControlGroup WHERE RoleID=@role AND GroupID=@group", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@role", id);
cmd.Parameters.AddWithValue("@group", groupID);
System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
this.id = reader.GetInt32(0);
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Инициализация класса роли группы элементов управления] ", ex);
}
}
}
}
/// <summary>
/// Сохранение привязки роли к группе
/// </summary>
public void Save()
{
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(@"IF((SELECT COUNT(*) FROM Authorization_RoleToControlGroup WHERE RoleID=@id AND GroupID=@group)=0)
INSERT INTO Authorization_RoleToControlGroup(RoleID,GroupID) VALUES(@id,@group)", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@id", this.id);
cmd.Parameters.AddWithValue("@group", this.GroupID);
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Сохранение роли группы элементов управления] ", ex);
}
}
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
namespace Ekzo.Web.Security.Utilization.Authorization
{
/// <summary>
/// Описывает роли из БД ConsUser
/// </summary>
public class SystemRole
{
/// <summary>
/// Идентификатор роли из базы разграничения прав
/// </summary>
public int id { get; private set; }
/// <summary>
/// Идентификатор роли из БД ConsUser
/// </summary>
public int baseID { get; private set; }
/// <summary>
/// Имя роли
/// </summary>
public string Role { get; private set; }
public int ActionGroup { get; private set; }
public SystemRole() { }
public SystemRole(string role)
{
InitClass(role);
}
public SystemRole(int actionGorup, string role)
{
InitClass(role, actionGorup);
}
public SystemRole(int baseID, int actionGroup = 0)
{
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Ekzo.Web.Configuration.StringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("SELECT group_name FROM groups WHERE group_id=@id", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@id", baseID);
System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
this.Role = reader.GetString(0);
this.baseID = baseID;
this.ActionGroup = actionGroup;
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Инициализация роли из справочника] ", ex);
}
}
}
}
private void InitClass(string role, int actionGroup = -1)
{
this.ActionGroup = actionGroup;
this.Role = role;
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("SELECT * FROM Authorization_RoleToActionGroup WHERE ActionGroup=@groupID AND Role=@role", conn))
{
try
{
if (actionGroup == -1) cmd.CommandText = "SELECT * FROM Authorization_RoleToActionGroup WHERE Role=@role";
conn.Open();
cmd.Parameters.AddWithValue("@groupID", actionGroup);
cmd.Parameters.AddWithValue("@role", role);
System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
this.id = reader.GetInt32(0);
this.Role = reader.GetString(2);
this.ActionGroup = reader.GetInt32(1);
}
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Инициализация роли] ", ex);
}
}
}
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Ekzo.Web.Configuration.StringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("SELECT group_id FROM groups WHERE group_name=@name", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@name", this.Role);
System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
this.baseID = reader.GetInt32(0);
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Инициализация роли. Получение роли из справочника] ", ex);
}
}
}
}
/// <summary>
/// Создание новой роли
/// </summary>
/// <param name="Name">Название роли</param>
/// <returns></returns>
public static SystemRole CreateRole(string Name)
{
SystemRole role = new SystemRole();
role.Role = Name;
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Ekzo.Web.Configuration.StringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("INSERT INTO groups(group_id,group_name) SELECT MIN(group_id)-1,@name FROM groups WHERE group_id>-1000", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@name", Name);
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT group_id FROM groups WHERE group_name=@name";
System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
role.baseID = reader.GetInt32(0);
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Добавление роли в справочник] ", ex);
}
}
}
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("INSERT INTO Authorization_RoleToActionGroup(ActionGroup,Role) VALUES(@group,@name)", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@name", role.Role);
cmd.Parameters.AddWithValue("@group", -1);
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Добавление роли в таблицу безопасности] ", ex);
}
}
}
role.ActionGroup = -1;
return role;
}
/// <summary>
/// Получает список ролей пользователя
/// </summary>
/// <param name="employeeID">Идентификатор сотрудника</param>
/// <returns></returns>
public static string[] GetEmployeeRoles(int employeeID)
{
List<string> roles = new List<string>();
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.StringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("SELECT group_name FROM employee2group INNER JOIN groups ON intranet_employee2group.group_id = groups.group_id WHERE employee_id=@employeeID ORDER BY group_name", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@employeeID", employeeID);
System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
roles.Add(reader.GetString(0));
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Получение ролей пользователя в системе] ", ex);
}
}
}
List<string> roleToDelete = new List<string>();
foreach (string role in roles)
if (!HttpContext.Current.User.IsInRole(role)) roleToDelete.Add(role);
for (int i = 0; i < roleToDelete.Count; i++)
roles.Remove(roleToDelete[i]);
return roles.ToArray();
}
/// <summary>
/// Сохранение роли
/// </summary>
public void Save()
{
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(@"
IF((SELECT COUNT(*) FROM Authorization_RoleToActionGroup WHERE id=@id OR Role=@name AND ActionGroup=@groupID)=0)
INSERT INTO Authorization_RoleToActionGroup(ActionGroup,Role) VALUES(@groupID, @name)
ELSE
UPDATE Authorization_RoleToActionGroup SET ActionGroup=@groupID, Role=@name WHERE id=@id", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@id", this.id);
cmd.Parameters.AddWithValue("@name", this.Role);
cmd.Parameters.AddWithValue("@groupID", this.ActionGroup);
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT * FROM Authorization_RoleToActionGroup WHERE Role=@name AND ActionGroup=@groupID";
System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
this.id = reader.GetInt32(0);
this.ActionGroup = reader.GetInt32(1);
this.Role = reader.GetString(2);
}
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Сохранение роли в системе безопасности] ", ex);
}
}
}
}
/// <summary>
/// Удаление роли
/// </summary>
/// <remarks>Удаление производится как из таблицы базы раграничения прав, так и из ConsUser</remarks>
public void Delete()
{
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("DELETE FROM Authorization_RoleToActionGroup WHERE id=@id", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@id", this.id);
cmd.ExecuteNonQuery();
cmd.CommandText = "DELETE FROM Authorization_RoleToActionGroup WHERE ActionGroup=@id";
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Удаление роли из системы безопасности] ", ex);
}
}
}
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Ekzo.Web.Configuration.StringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("DELETE FROM employee2group WHERE group_id=@groupID", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@groupID", this.baseID);
cmd.ExecuteNonQuery();
cmd.Parameters.AddWithValue("@name", this.Role);
cmd.CommandText = "DELETE FROM groups WHERE group_name=@name";
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Удаление привязки пользователей к роли в справочнике] ", ex);
}
}
}
}
#region StaticFields
/// <summary>
/// Получение списка всех ролей системы безопасности
/// </summary>
/// <returns></returns>
public static List<string> GetAllRoles()
{
List<string> result = new List<string>();
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("SELECT DISTINCT Role FROM Authorization_RoleToActionGroup ORDER BY Role", conn))
{
try
{
conn.Open();
System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
result.Add(reader.GetString(0));
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Получение списка ролей в системе безопасности] ", ex);
}
}
}
return result;
}
/// <summary>
/// Получение списка всех полей интранета
/// </summary>
/// <returns></returns>
public static List<string> GetAllIntranetRoles()
{
List<string> result = new List<string>();
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Ekzo.Web.Configuration.StringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("SELECT DISTINCT group_name FROM groups ORDER BY group_name", conn))
{
try
{
conn.Open();
System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
result.Add(reader.GetString(0));
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Получение списка ролей из справочника] ", ex);
}
}
}
return result;
}
/// <summary>
/// Получение списка пользователей для роли
/// </summary>
/// <param name="role">Имя роли</param>
/// <returns></returns>
public static List<BaseClasses.Employee> EmployeesInRole(string role)
{
List<BaseClasses.Employee> result = new List<BaseClasses.Employee>();
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Ekzo.Web.Configuration.StringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("SELECT intranet_employee2group.employee_id FROM groups INNER JOIN intranet_employee2group on groups.group_id=intranet_employee2group.group_id WHERE group_name=@groupName", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@groupName", role);
System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
result.Add(new BaseClasses.Employee(reader.GetInt32(0)));
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Получение списка пользователей, имеющих роль] ", ex);
}
}
}
return result;
}
/// <summary>
/// Получение списка ролей для группы
/// </summary>
/// <param name="GroupName">Имя группы</param>
/// <returns></returns>
public static SystemRole[] GetGroupRoles(string GroupName)
{
ActionGroup group = new ActionGroup(GroupName);
return GetGroupRoles(group.id);
}
/// <summary>
/// Получение списка ролей для группы
/// </summary>
/// <param name="groupID">Идентификатор группы по БД разграничения правд доступа</param>
/// <returns></returns>
public static SystemRole[] GetGroupRoles(int groupID)
{
List<SystemRole> rolesList = new List<SystemRole>();
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.ConnectionStringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("SELECT * FROM Authorization_RoleToActionGroup WHERE ActionGroup=@groupID", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@groupID", groupID);
System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
rolesList.Add(new SystemRole(reader.GetInt32(1), reader.GetString(2)));
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Получение ролей группы действий] ", ex);
}
}
}
return rolesList.ToArray();
}
public static int? IntranetRoleID(string roleName)
{
int? result = null;
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[Configuration.StringName].ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("SELECT group_id FROM groups WHERE group_name=@name", conn))
{
try
{
conn.Open();
cmd.Parameters.AddWithValue("@name", roleName);
using (System.Data.SqlClient.SqlDataReader reader = cmd.ExecuteReader())
while (reader.Read())
result = reader.GetInt32(0);
}
catch (Exception ex)
{
Configuration.s_log.Error("[Ошибка модуля авторизации] [Получение идентификатора роли]", ex);
}
}
}
return result;
}
#endregion
}
}
А теперь перейдем к реализации атрибута, наследуемого от авторизационного атрибута (AuthorizeAttribute), который будет применяться к методам контроллеров и определять, имеет ли текущий пользователь право на доступ к странице сайта (тут формулировка немного некорректная, но для простоты понимания пусть останется такой).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Ekzo.Web.Security.Utilization
{
/// <summary>
/// Атрибут обеспечивающий разграничение прав доступа к методам контроллеров
/// </summary>
[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = false)]
public class ActionAuthorization : AuthorizeAttribute
{
/// <summary>
/// Имя метода контроллера
/// </summary>
public string ActionName { get; set; }
/// <summary>
/// Выполняет проверку на право доступа к методу
/// </summary>
/// <param name="httpContext">Контекст</param>
/// <returns>Если право есть, выполняет метод. Иначе перенаправляет пользователя на страницу ошибки.</returns>
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool result = false;
var isAuthorized = base.AuthorizeCore(httpContext);
if (!isAuthorized) return false;
Authorization.Action currentAction = new Authorization.Action(this.ActionName);
//Если действие не добавлено в БД, сохраняем.
if (!currentAction.IsExist()) currentAction.Save();
//Если действие деактивировано, пускаем всех.
if (!currentAction.Active) return true;
string[] currentUserRoles = AuthLib.Helpers.RoleProviderHelper.GetUserGroups(httpContext.User.Identity.Name);
foreach (string role in currentUserRoles)
{
if (currentAction.ActionGroups != null && currentAction.ActionGroups.Where(o => o.Roles.Select(n => n.Role).Contains(role)).Count() != 0) { result = true; break; }
}
return result;
}
}
}
В реализации ничего сложного нет. Мы переопределяем функцию AuthorizeCore, которая возвратит true в случае, если пользователь имеет право на доступ или в случае, если администратор отключил авторизацию в настройках. Если пользователь не имеет права на доступ, возвращается false и перенаправляет на страницу ошибки 401.
Единственный момент, на который хочу обратить внимание, находится в этой строчке:
if (!currentAction.IsExist()) currentAction.Save();
Здесь выполняется проверка на существование правила для проверяемого метода. Если правила нет, создаем его. Сделано это для того, чтобы не выполнять добавление правил для новых методов, а добавлять их автоматически (забегая вперед скажу, что внутри выполняется создание разрешающего правила для администраторов, так что доступ получат все, кто имеет соответствующие права).
Осталось написать расширения для стандартных типов, которые чаще всего используются в представлениях (и не только).
using System;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Ekzo.Web.Security
{
/// <summary>
/// Аттрибут разграничения доступа к контролу
/// </summary>
public class ControlAccesSecurity
{
/// <summary>
/// Проверка права доступа сотрудника к контролу
/// </summary>
/// <param name="controlName">Название контрола, описывающее его</param>
/// <returns>Если пользователь имеет право доступа - возвращает true, иначе false</returns>
public static bool HasControlAccess(string controlName)
{
BaseClasses.Employee employee = new BaseClasses.Employee(AuthLib.Helpers.RoleProviderHelper.GetUserId(HttpContext.Current));
Utilization.Authorization.PageControl currentControl = new Utilization.Authorization.PageControl(controlName);
foreach (Utilization.Authorization.PageControlsGroup group in currentControl.Groups)
if (group.Roles.Where(o => Utilization.Authorization.SystemRole.GetEmployeeRoles(employee.Id).Contains(o.Role)).Count() != 0)
return true;
return false;
}
}
}
namespace Ekzo.Web.Security.SecurityExtensions
{
/// <summary>
/// Расширения для базовых классов, обеспечивающие разграничение правд доступа
/// </summary>
public static class StringExtensions
{
/// <summary>
/// Проверка права доступа сотрудника к контролу
/// </summary>
/// <param name="controlName">Название контрола, описывающее его</param>
/// <returns>Если пользователь имеет право доступа - возвращает контро, иначе пустую строку</returns>
public static MvcHtmlString HasControlAccess(this MvcHtmlString s, string controlName)
{
BaseClasses.Employee employee = new BaseClasses.Employee(AuthLib.Helpers.RoleProviderHelper.GetUserId(HttpContext.Current));
Utilization.Authorization.PageControl currentControl = new Utilization.Authorization.PageControl(controlName);
foreach (Utilization.Authorization.PageControlsGroup group in currentControl.Groups)
if (group.Roles.Where(o => Utilization.Authorization.SystemRole.GetEmployeeRoles(employee.Id).Contains(o.Role)).Count() != 0)
return s;
return MvcHtmlString.Create("");
}
/// <summary>
/// Проверка права доступа сотрудника к контролу
/// </summary>
/// <param name="controlName">Название контрола, описывающее его</param>
/// <returns>Если пользователь имеет право доступа - возвращает контро, иначе пустую строку</returns>
public static IHtmlString HasControlAccess(this IHtmlString s, string controlName)
{
BaseClasses.Employee employee = new BaseClasses.Employee(AuthLib.Helpers.RoleProviderHelper.GetUserId(HttpContext.Current));
Utilization.Authorization.PageControl currentControl = new Utilization.Authorization.PageControl(controlName);
foreach (Utilization.Authorization.PageControlsGroup group in currentControl.Groups)
if (group.Roles.Where(o => Utilization.Authorization.SystemRole.GetEmployeeRoles(employee.Id).Contains(o.Role)).Count() != 0)
return s;
return MvcHtmlString.Create(string.Empty);
}
/// <summary>
/// Проверка права доступа сотрудника к контролу
/// </summary>
/// <param name="controlName">Название контрола, описывающее его</param>
/// <returns>Если пользователь имеет право доступа - возвращает контро, иначе пустую строку</returns>
public static string HasControlAccess(this string s, string controlName)
{
BaseClasses.Employee employee = new BaseClasses.Employee(AuthLib.Helpers.RoleProviderHelper.GetUserId(HttpContext.Current));
Utilization.Authorization.PageControl currentControl = new Utilization.Authorization.PageControl(controlName);
foreach (Utilization.Authorization.PageControlsGroup group in currentControl.Groups)
if (group.Roles.Where(o => Utilization.Authorization.SystemRole.GetEmployeeRoles(employee.Id).Contains(o.Role)).Count() != 0)
return s;
return String.Empty;
}
}
/// <summary>
/// Расширения для TagBuilder'a обеспечивающие разграничение прав доступа
/// </summary>
public static class TagBuilderExtensions
{
/// <summary>
/// Проверка права доступа сотрудника к контролу
/// </summary>
/// <param name="controlName">Название контрола, описывающее его</param>
/// <returns>Если пользователь имеет право доступа - возвращает контро, иначе пустую строку</returns>
public static TagBuilder HasControlAccess(this TagBuilder s, string controlName)
{
BaseClasses.Employee employee = new BaseClasses.Employee(AuthLib.Helpers.RoleProviderHelper.GetUserId(HttpContext.Current));
Utilization.Authorization.PageControl currentControl = new Utilization.Authorization.PageControl(controlName);
foreach (Utilization.Authorization.PageControlsGroup group in currentControl.Groups)
if (group.Roles.Where(o => Utilization.Authorization.SystemRole.GetEmployeeRoles(employee.Id).Contains(o.Role)).Count() != 0)
return s;
return new TagBuilder("b");
}
}
}
Это все, что понадобится для работы системы разделения прав.
[ActionAuthorization(ActionName = "Запросы в работе")]
public ActionResult RequestsInWork()
{
ViewBag.Title = "Запросы в работе";
return View();
}
...
@Html.MainMenu().HasControlAccess("Главное меню")
...
Пояснение
Здесь я постараюсь раскрыть смысл всего безобразия, описанного ранее.
Во-первых, созданная структура позволяет управлять не только методами контроллеров, но и «любыми» другими элементами на страницах сайтов.
Во-вторых, подготовлена инфраструктура модуля, позволяющая выполнять связки пользователь-роль-«группы объектов»-«защищаемый объект» в любой конфигурации. То есть Любой пользователь может быть в любой роли. Роль в свою очередь может быть привязана к любой группе защищаемых объектов. Объект может содержаться в любой роли.
Такая витиеватая связка позволяет создать любое сочетание защищаемых объектов и ролей, которым они доступны. Поэтому при появлении новой роли мы можем как выдать права уже присвоенные другой роли в системе, так и выдать уникальный набор прав. Если придет заказчик и скажет «хочу новую роль, которой будет доступно то-то и то-то» все сводится к выполнению простых действий, не требующих изменений в коде проекта.
Расширения, созданные в модуле, позволяют также гибко управлять выводимыми данными например в собственных методах HtmlHelper'а.
На практике данный метод разделения прав неплохо работает и с AJAX запросами.
Немного вкусняшки
Для более удобного управления напишем класс-конфигуратор
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using log4net;
namespace Ekzo.Web
{
public static class Configuration
{
/// <summary>
/// Название строки подключения к БД в файле web.config, указывающей на базу с таблицами авторизации.
/// Поумолчанию DataSource
/// </summary>
public static string ConnectionStringName = "DataSource";
/// <summary>
/// Название строки подключения к БД в файле web.config, указывающей на базу
/// Поумолчанию
/// </summary>
public static string StringName = "ConsUser";
/// <summary>
/// Название проекта
/// </summary>
public static string ProjectName = "Project Name";
/// <summary>
/// Объект лога log4net
/// </summary>
public static ILog s_log = null;
/// <summary>
/// Список таблиц системы безопасности
/// </summary>
private static string[] tables = { "Authorization_ActionGroups",
"Authorization_Actions",
"Authorization_ActionToGroup",
"Authorization_Controls",
"Authorization_ControlsGroup",
"Authorization_ControlToGroup",
"Authorization_RoleToActionGroup",
"Authorization_RoleToControlGroup"};
/// <summary>
/// Проверка на существование всех таблиц в БД
/// </summary>
/// <returns>Если хотя бы одна таблица не найдена в БД, значение становится ложным</returns>
public static bool BaseHasTables()
{
List<string> dbTables = new List<string>();
using (SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[ConnectionStringName].ConnectionString))
{
using (SqlCommand cmd = new SqlCommand("select TABLE_NAME from information_schema.tables WHERE TABLE_NAME LIKE 'Authorization_%'", conn))
{
try
{
conn.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
dbTables.Add(reader.GetString(0));
}
foreach (string securityTable in tables)
if (dbTables.Contains(securityTable))
dbTables.Remove(securityTable);
}
catch (Exception ex)
{
Configuration.s_log.Error("[Ошибка модуля авторизации] [Проверка таблиц безопасности] ", ex);
}
}
}
if (dbTables.Count == 0) return false; else return true;
}
/// <summary>
/// Выполняет создание таблиц безопасности в БД
/// </summary>
/// <param name="superAdminGroup">Имя группы в справочнике, пользователи которой будут назначены суперадминистраторами системы</param>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2100:Review SQL queries for security vulnerabilities")]
public static void CreateSecurityTables(string superAdminGroup = null)
{
List<string> dbTables = new List<string>();
using (SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[ConnectionStringName].ConnectionString))
{
using (SqlCommand cmd = new SqlCommand("SELECT TABLE_NAME FROM information_schema.tables WHERE TABLE_NAME LIKE 'Authorization_%'", conn))
{
try
{
conn.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
dbTables.Add(reader.GetString(0));
}
foreach (string securityTable in tables)
if (dbTables.Contains(securityTable))
dbTables.Remove(securityTable);
cmd.Parameters.AddWithValue("@database", conn.Database);
if (dbTables.Count == 0)
foreach (string table in tables)
dbTables.Add(table);
if (dbTables.Count != 0)
foreach (string table in dbTables)
{
switch (table)
{
case "Authorization_ControlsGroup":
cmd.CommandText = "USE " + conn.Database + @"
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
SET ANSI_PADDING ON
CREATE TABLE [dbo].[Authorization_ControlsGroup](
[id] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](500) NOT NULL,
CONSTRAINT [PK_Authorization_ControlsGroup] PRIMARY KEY CLUSTERED
([id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
SET ANSI_PADDING OFF
SET IDENTITY_INSERT [dbo].[Authorization_ControlsGroup] ON
INSERT INTO [dbo].[Authorization_ControlsGroup](id,Name) VALUES(-1,'Контролы суперадмина')
SET IDENTITY_INSERT [dbo].[Authorization_ControlsGroup] OFF";
break;
case "Authorization_Actions":
cmd.CommandText = "USE " + conn.Database + @"
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
SET ANSI_PADDING ON
CREATE TABLE [dbo].[Authorization_Actions](
[id] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](500) NOT NULL,
[Active] [bit] NOT NULL,
CONSTRAINT [PK_Authorization_Actions] PRIMARY KEY CLUSTERED
([id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
SET ANSI_PADDING OFF
ALTER TABLE [dbo].[Authorization_Actions] ADD CONSTRAINT [DF_Authorization_Actions_Active] DEFAULT ((1)) FOR [Active]";
break;
case "Authorization_ActionToGroup":
cmd.CommandText = "USE " + conn.Database + @"
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
CREATE TABLE [dbo].[Authorization_ActionToGroup](
[id] [int] IDENTITY(1,1) NOT NULL,
[ActionID] [int] NOT NULL,
[GroupID] [int] NOT NULL,
CONSTRAINT [PK_Authorization_ActionToGroup] PRIMARY KEY CLUSTERED
([id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]";
break;
case "Authorization_Controls":
cmd.CommandText = "USE " + conn.Database + @"
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
SET ANSI_PADDING ON
CREATE TABLE [dbo].[Authorization_Controls](
[id] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](500) NOT NULL,
CONSTRAINT [PK_Authorize_Controls] PRIMARY KEY CLUSTERED
([id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
SET ANSI_PADDING OFF";
break;
case "Authorization_ControlToGroup":
cmd.CommandText = "USE " + conn.Database + @"
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
CREATE TABLE [dbo].[Authorization_ControlToGroup](
[id] [int] IDENTITY(1,1) NOT NULL,
[ControlID] [int] NOT NULL,
[GroupID] [int] NOT NULL,
CONSTRAINT [PK_Authorization_ControlToGroup] PRIMARY KEY CLUSTERED
( [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]";
break;
case "Authorization_RoleToActionGroup":
cmd.CommandText = "USE " + conn.Database + @"
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
SET ANSI_PADDING ON
CREATE TABLE [dbo].[Authorization_RoleToActionGroup](
[id] [int] IDENTITY(1,1) NOT NULL,
[ActionGroup] [int] NOT NULL,
[Role] [varchar](500) NOT NULL,
CONSTRAINT [PK_Authorization_RoleToActionGroup] PRIMARY KEY CLUSTERED
([id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
SET ANSI_PADDING OFF
ALTER TABLE [dbo].[Authorization_RoleToActionGroup] ADD CONSTRAINT [DF_Authorization_RoleToActionGroup_ActionGroup] DEFAULT ((-1)) FOR [ActionGroup]";
break;
case "Authorization_RoleToControlGroup":
cmd.CommandText = "USE " + conn.Database + @"
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
CREATE TABLE [dbo].[Authorization_RoleToControlGroup](
[id] [int] IDENTITY(1,1) NOT NULL,
[RoleID] [int] NOT NULL,
[GroupID] [int] NOT NULL,
CONSTRAINT [PK_Authorization_RoleToControlGroup] PRIMARY KEY CLUSTERED
([id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]";
break;
case "Authorization_ActionGroups":
cmd.CommandText = "USE " + conn.Database + @"
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
SET ANSI_PADDING ON
CREATE TABLE [dbo].[Authorization_ActionGroups](
[id] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](500) NOT NULL,
[active] [bit] NOT NULL,
CONSTRAINT [PK_Authorization_ActionGroups] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
SET ANSI_PADDING OFF
ALTER TABLE [dbo].[Authorization_ActionGroups] ADD CONSTRAINT [DF_Authorization_ActionGroups_active] DEFAULT ((1)) FOR [active]
SET IDENTITY_INSERT [dbo].[Authorization_ActionGroups] ON
INSERT INTO [dbo].[Authorization_ActionGroups](id,Name) VALUES(0,'Все разделы')
SET IDENTITY_INSERT [dbo].[Authorization_ActionGroups] OFF";
break;
}
cmd.ExecuteNonQuery();
}
if (!string.IsNullOrEmpty(superAdminGroup) && Web.Security.Utilization.Authorization.SystemRole.IntranetRoleID(superAdminGroup) != null)
{
cmd.CommandText = @"INSERT INTO Authorization_RoleToActionGroup(ActionGroup,Role) VALUES(0,@group)
INSERT INTO Authorization_RoleToControlGroup(RoleID,GroupID) VALUES(@role,-1)";
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("@group", superAdminGroup);
cmd.Parameters.AddWithValue("@role", Web.Security.Utilization.Authorization.SystemRole.IntranetRoleID(superAdminGroup));
cmd.ExecuteNonQuery();
}
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка модуля авторизации] [Создание таблиц безопасности] ", ex);
}
}
}
}
public static void RecreateTables(string superAdminGroup = null)
{
string command = "DROP TABLE {0}";
using (SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[ConnectionStringName].ConnectionString))
{
using (SqlCommand cmd = new SqlCommand("", conn))
{
try
{
conn.Open();
foreach (string table in tables)
{
cmd.CommandText = string.Format(command, table);
cmd.ExecuteNonQuery();
}
}
catch (Exception ex)
{
if (Configuration.s_log != null)
Configuration.s_log.Error("[Ошибка молудя авторизации] [Ошибка пересоздания таблиц безопасности] ", ex);
}
}
}
CreateSecurityTables(superAdminGroup);
}
}
}
Этот класс содержит все настройки и как бонус функции, необходимые для управления таблицами модуля.
Проект на GitHub
Вместо заключения
Описанный мной класс Employee вполне может быть опущен, но в своих проектах я часто использую его, поэтому не стал убирать из модуля.
Для управления ролями был создан интерфейс, позволяющий быстро и удобно создавать/удалять/менять роли и привязки. Но он работает на более новой версии модуля, поэтому его я не выкладываю.
Еще раз прошу не кидать помидорами. Весь приведенный код и проект, расположенный на GitHub'е являются первой версией и содержат большое количество говнокода.
Автор: ParaPilot