Разделяй и властвуй. Или система разделения прав для ASP MVC

    Очень часто в работе сталкиваюсь с проблемой разделения прав доступа к разделам сайта и элементам управления.
    Сначала мне хватало инструментов, которые предоставляет ASP MVC «из коробки», но, со временем, я столкнулся с необходимостью создания своего инструмента разделения прав. Если тебе, уважаемый %habrauser%, интересно как можно решить эту проблему, добро пожаловать под кат.

    Немного лирики


    В одном из проектов столкнулся с проблемой разделения прав доступа к разделам и элементам сайта. Это внутренний сайт компании на котором сотрудники могут планировать свой отпуск. ТЗ было написано, на удивление, хорошо. Работа шла ударными темпами и уже через месяц работы был готов рабочий прототип. Все были в восторге ровно до того момента, как не начались «уточнения» по работе системы. А так как бюрократ сидит в нашем человеке с рождения, была куча согласований и обсуждений, результатом которых было что-то вроде такого: «Все отлично. Но вот это не должен видеть обычный пользователь. А это должен видеть только администратор. А это должен видеть только особо секретный администратор и никто другой!». И это, к сожалению, не конец бурной фантазии заказчика.
    Стандартными средствами управление ролями и доступами сделать можно, но очень уж муторно. Поэтому я взялся за создание модуля разделения прав доступа, которым можно легко управлять.

    Приступая к работе


    Для начала были выведены основные требования к модулю.
    1. Простое разделение прав доступа к методам контроллеров (по принципу работы аттрибута Authorize)
    2. Простой в работе механизм разделения доступа к элементам сайта
    3. Возможность создавать роли с любыми вариациями доступа
    4. Возможность использования в разных проектах

    Потом была проведена «работа» по рисованию различных схем и просмотра огромной кучи материалов по теме. В итоге была выработана концепция модуля.
    Данные, необходимые для работы модуля, будут храниться в базе MSSQL (а на чем же еще, если пишем на c#). Централизованное хранилище делать не стал из-за особенностей структуры корпоративной сети и идеи использования (в теории) на любом проекте. Поэтому будем писать в базы проектов свой набор данных модуля.
    Также исходя из идеи, что модуль должен работать с любым проектом, он должен читать настройки из файла web.config проекта, к которому подключен модуль.
    Ну и пусть модуль умеет подготавливать для себя базу и делает начальную конфигурацию, чтобы развертывание на новом проекте было простым как… кхм. Ну вы поняли.
    И на вкусное, пусть он по умолчанию заносит все вновь созданные или добавленные элементы и разделы в таблицы и дает доступ «суперадмину», чтобы при работы не пришлось каждый раз лезть в настройки.

    Начало работы

    Для начала хочу сказать пару слов о получившемся модуле. Для своей работы он использует самописный RoleProvider. И причиной его использования опять же стали особенности корпоративной сети. Таким образом на одном из серверов сделан справочник в котором находятся все данные по сотрудниками и привязка к доменному логину. Не спрашивайте почему. Это устоявшееся положение вещей.
    Так вот, для внутренних нужд в справочнике есть группы для сотрудников. Поэтому был написан свой провайдер ролей, который не только выполнял свои основные функции, но оперировал группами в справочнике на сервере. Его приводить я не буду, так как особого интереса он не представляет и ничего нового в написании провайдера вы не найдете. (в фрагментах кода будет встречаться обращение к пространству имен AuthLib, которое и содержит провайдер ролей).

    Пока не пошел код, я хочу попросить прощения за комментарии и другой мусор в коде. Приведенный код является устаревшим(в реалиях текущих проектов) и приведен только для демонстрации идеи.

    Первым делом создаем класс, описывающий пользователя. Так будет проще работать в будущем.

    Класс 'Cотрудник'
    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'е являются первой версией и содержат большое количество говнокода.

    Similar posts

    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 9

      +1
      Dependency Injection — нет, не слышали? А принцип единственной ответственности? А то, что представление должно содержать минимум логики (и поэтому все проверки выносятся в контроллер и фильтры)? Про магические строки я и вовсе не упоминаю.

      Ну и да, отдельно хочется услышать, чем вам не угодил стандартный механизм авторизации в MVC.
        0
        Ну и да, отдельно хочется услышать, чем вам не угодил стандартный механизм авторизации в MVC.

        Механизм авторизации предоставляемый в MVC меня полностью устраивает. Но очень часто возникают ситуации, когда на уже готовой странице заказчик требует разместить/скрыть ссылку, которая должна отображаться только руководителям отделов. Через 2 дня, посовещавшись, заказчик еще требует разместить пару ссылок, но уже для руководителей высшего звена. А это тянет за собой очень много неприятностей. Делать новую страницу только для руководителей, где отличие только в наличии 1-2 ссылок, тоже не вариант. Чем больше сущностей, тем сложнее поддержка всего проекта в целом.
        Прошу прощения, может я не дошел до темных недр стандартного механизма, но даже в предлагаемых NuGet'ом системах я не видел, чтобы была возможность раздавать права на доступ до уровня элемента на странице.
        Я не говорил, что мой вариант претендует на гениальность и уж точно не является единственно правильным решением. Но я поделился своим опытом выхода из ситуации, когда заказчик меняет задачу на ходу и не один раз за неделю.
        Приведенный код откровенно не рабочий и уж тем более речь не идет о нормализации. Но общая идея проиллюстрирована.
        Сейчас модуль работает в десятке проектов и был написан с применением всех правил хорошего тона. И будьте уверены, DI и остальные премудрости современного программирования в нем присутствуют. Но выложить его я не мог, так как внутри много вещей, составляющих коммерческую тайну.

        +2
        SQL код в классах сущностей убил наповал. Так нельзя делать даже ради примеров. Ну можно конечно, но однозначно не стоит.
          0
          Все, что вам нужно, уже реализовано в WIF. Наследуйтесь от ClaimsAuthorizationManager и используйте атрибут [ClaimsPrincipalPermission(SecurityAction.Demand, Operation = "...", Resource = "...")].
            0
            — возьми уже Entity Framework. Или BL Toolkit. Или хотя-бы хелперы какие-нибудь напиши на крайняк. Рутинный этот код с SQLCommand в 21-м веке выглядит дико
            — грузи все что нужно для прав доступа сразу, желательно в один запрос. Можно грузить один раз на запрос в фильтре и класть в RequestContext, можно класть в сессию. Я ведь правильно понимаю что каждый вызов хелпера у тебя — это обращение к базе?
            — не нужно делать SQL-запросы в конструкторе. Вообще размазывать загрузку из базы по классам — плохая идея.
            — логируй исключения, прикрути библиотеку для логирования, подцепи какой-нибудь IoC с аспектами и положи логирование в аспекты
            — char.Parse(" ") — почему не ' '?
            — вешать extension-методы для авторизации на класс String — весьма сомнительное решение
              0
              Господа, отвечу всем и сразу.
              Во-первых, я уже писал, что данные код не является продакшн кодом. Естественно, что в «боевой версии» все сделано красиво, удобно и с применением всех магических техник.
              Во-вторых, весь код, работающий с БД реализован с применением паттерна Repository. Обращение к БД идет с помощью LINQ2SQL.
              Dependency Injection — нет, не слышали?

              Конечно слышал и применяю на практике. Код, приведенный в статье является прототипом. Возможно, из-за недостатка опыта работы с DI, мне сходу бывает трудно написать готовый код сразу.
                0
                Разместить/скрыть ссылку — хелпером в зависимости от роли или через sitemap, тоже самое «Элементы на страницах» — partial или ActionResult. Да, и из одной Html.LinkAction() тоже, в том числе. с отделением логики от представлений в контроллер.
                Про свою базу пользователей при готовом AD — я, пожалуй, промолчу. Про int в качестве userid, если в AD есть нормальный GUID для сущности пользователя — тоже. Про использование групп из AD, должностей, отделов и возможность использовать вагон готовых и кастомных полей — видимо, упоминать и не стоит.

                Про правила хорошего тона — на вкус и цвет, как говорится, поэтому спорить не буду.
                  0
                  Про свою базу пользователей при готовом AD

                  В том то и дело, что AD не ведут, а уж указание должностей и т.п. речи не идет, поэтому и используется БД с справочником сотрудников.
                  0
                  А как с производительностью? :)
                  Реализовывал подобную систему раздачи прав — сразу сделал загрузку всех правил в синглтон, и периодическое обновление кэша (что бы базу пореже дёргать).
                  По названиям, рекомендую в коде использовать английские имена наподобие «ServiceDesk.canSetConsider», «ServiceDesk.canTakeProblem» а в админке отображать имя и русский description — так удобнее искать, делая разные сортировки, группировки и фильтры.

                  Only users with full accounts can post comments. Log in, please.