Основы управления ролью ASP.NET Core 2.0. Управление динамическим меню с использованием Dependency Injection

Tags: Visual Studio, SQL Server

Введение

В этой статье мы подробно рассмотрим, как отобразить динамическое меню на основе ролей после входа пользователя в систему. Для этого мы создадим таблицу главного меню и введем несколько записей, чтобы отобразить меню и связать URL-адрес с меню на основе зарегистрированной роли пользователя.

Здесь мы посмотрим, как:

  • создавать пользователей admin и manager по умолчанию;
  • создать таблицу MenuMaster и вставить несколько примеров записей для ролей admin и manager для отображения меню;
  • перенаправлять не прошедших проверку пользователей на страницу входа в систему;
  • отображать меню динамически на основе зарегистрированного пользователя.

Скачать исходный код: Download

Подготовка

Предварительные требования

Убедитесь, что на вашем компьютере установлены все необходимые компоненты. Если нет, загрузите и установите их все по одному.

  1. Сначала загрузите и установите Visual Studio 2017 из этой ссылки
  2. SQL Server 2014 или выше

Использование кода

Шаг 1. Создание базы данных.

Мы будем использовать общую базу данных для таблиц ASP.NET Identity и для наших собственных новых таблиц.

Для управления меню на основе ролей нам необходимо создать таблицу отношений между таблицей ролей ASP.NET и нашей таблицей меню.

Давайте подробно рассмотрим, как создать нашу новую таблицу меню, которая имеет отношение к таблице ASP.NET Identity AspNetRoles.

Здесь мы можем видеть поля, используемые для MenuMaster:




Во-первых, мы создадим базу данных и установим строку подключения в файле appsettings.json для DefaultConnection с нашим новым подключением к базе данных. Мы будем использовать эту базу данных для создания таблицы основных идентификаторов ASP.NET.

 

Создание базы данных

Запустите следующий скрипт, чтобы создать нашу таблицу MenuMaster базы данных и  пример вставки строк сценария Menu.

USE MASTER       
GO       
      
-- 1) Check for the Database Exists. If the database exists, then drop and create new DB       
IF EXISTS (SELECT [name] FROM sys.databases WHERE [name] = 'AttendanceDB' )       
DROP DATABASE AttendanceDB       
GO       
      
CREATE DATABASE AttendanceDB       
GO              

USE AttendanceDB    
GO    
 
IF EXISTS ( SELECT [name] FROM sys.tables WHERE [name] = 'MenuMaster' )    
DROP TABLE MenuMaster    
GO    
   
CREATE TABLE MenuMaster    
(    
  MenuIdentity int identity(1,1),    
  MenuID VARCHAR(30)  NOT NULL,    
  MenuName VARCHAR(30)  NOT NULL,  
  Parent_MenuID  VARCHAR(30)  NOT NULL,  
  User_Roll [varchar](256) NOT NULL,   
  MenuFileName VARCHAR(100) NOT NULL,     
  MenuURL VARCHAR(500) NOT NULL,    
  USE_YN Char(1) DEFAULT 'Y',    
  CreatedDate datetime    
CONSTRAINT [PK_MenuMaster] PRIMARY KEY CLUSTERED          
(         
 [MenuIdentity] ASC   ,  
 [MenuID] ASC,    
 [MenuName] ASC      
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, _
ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]         
) ON [PRIMARY]       
  
select * from MenuMaster  
-- Insert Admin User Details
Insert into MenuMaster(MenuID ,MenuName,Parent_MenuID,User_Roll,MenuFileName,MenuURL,USE_YN,CreatedDate)
   Values('AUSER','ADMIN Dashboard','*','ADMIN','INDEX','ADMINC','Y',getDate())  
Insert into MenuMaster(MenuID ,MenuName,Parent_MenuID,User_Roll,MenuFileName,MenuURL,USE_YN,CreatedDate)
   Values('AAbout','About Admin','*','ADMIN','INDEX','ADMINAC','Y',getDate())   
Insert into MenuMaster(MenuID ,MenuName,Parent_MenuID,User_Roll,MenuFileName,MenuURL,USE_YN,CreatedDate)
   Values('LStock','Live Stock','AUSER','ADMIN','INDEX','StockC','Y',getDate())     
Insert into MenuMaster(MenuID ,MenuName,Parent_MenuID,User_Roll,MenuFileName,MenuURL,USE_YN,CreatedDate)
   Values('Profile','User Details','AUSER','ADMIN','INDEX','MemberC','Y',getDate())   
Insert into MenuMaster(MenuID ,MenuName,Parent_MenuID,User_Roll,MenuFileName,MenuURL,USE_YN,CreatedDate)
   Values('MUSER','Manager Dashboard','*','ADMIN','INDEX','ManagerC','Y',getDate())  
Insert into MenuMaster(MenuID ,MenuName,Parent_MenuID,User_Roll,MenuFileName,MenuURL,USE_YN,CreatedDate)
   Values('MAbout','About Manager','*','ADMIN','INDEX','ManagerAC','Y',getDate())   
Insert into MenuMaster(MenuID ,MenuName,Parent_MenuID,User_Roll,MenuFileName,MenuURL,USE_YN,CreatedDate)
   Values('Accounts','Account Details','MUSER','ADMIN','INDEX','AccountC','Y',getDate())    
   Insert into MenuMaster(MenuID ,MenuName,Parent_MenuID,User_Roll,MenuFileName,_
                          MenuURL,USE_YN,CreatedDate)
   Values('Inventory','Inventory Details','MUSER','ADMIN','INDEX','InventoryC','Y',getDate())  

-- Insert Manager User Details
Insert into MenuMaster(MenuID ,MenuName,Parent_MenuID,User_Roll,MenuFileName,MenuURL,USE_YN,CreatedDate)
   Values('MUSER','Manager Dashboard','*','Manager','INDEX','ManagerC','Y',getDate())  
Insert into MenuMaster(MenuID ,MenuName,Parent_MenuID,User_Roll,MenuFileName,MenuURL,USE_YN,CreatedDate)
   Values('MAbout','About Manager','*','Manager','INDEX','ManagerAC','Y',getDate())   
Insert into MenuMaster(MenuID ,MenuName,Parent_MenuID,User_Roll,MenuFileName,MenuURL,USE_YN,CreatedDate)
   Values('Accounts','Account Details','MUSER','Manager','INDEX','AccountC','Y',getDate())     
Insert into MenuMaster(MenuID ,MenuName,Parent_MenuID,User_Roll,MenuFileName,MenuURL,USE_YN,CreatedDate)
   Values('Inventory','Inventory Details','MUSER','Manager','INDEX','InventoryC','Y',getDate())   

select * from MenuMaster

select * from AspnetUserRoles

 

Здесь мы можем видеть формат, который мы используем в нашей таблице MenuMaster, чтобы вставлять наши записи для меню отображения на основе роли пользователя.

  • enuID = 'AUSER' (мы укажем уникальный идентификатор меню).
  • MenuName = 'ADMIN Dashboard' (мы укажем текст отображения меню),
  • Parent_MenuID = '*’ Если это главное меню, мы здесь будем указывать «*», иначе мы укажем MenuID предыдущих записей, чтобы выставить эту запись для отображения в качестве подменю).
  • User_Roll = 'ADMIN' (здесь мы укажем User Role - роль пользователя, если одно и то же меню должно использоваться для пользователей с несколькими ролями, таких как Admin, Manager, Accountant и т. д., тогда мы вставим те же детали меню с разными ролями пользователей. В нашем примере мы добавили те же детали меню, что и 'Manager Dashboard' для пользователей Admin и Manager, поскольку оба могут просматривать меню и страницу.).
  • MenuFileName = 'INDEX' (Здесь мы укажем наше логическое имя вида  которое будет отображаться при щелчке по меню).
  • MenuURL = 'ADMINC' (Здесь мы укажем наше имя контроллера которое будет отображаться при щелчке по меню).
  • USE_YN = 'Y' (Это необязательное поле, поскольку мы можем использовать его или не использовать для отображения меню).
  • CreatedDate = getDate() (Это также необязательно для ввода создания даты).

В этом демонстрационном приложении у нас уже есть все необходимые контроллеры и представления, которые будут отображаться, когда пользователь нажимает на меню.

 

Шаг 2. Создание своего  ASP.NET Core

После установки нашей Visual Studio 2017 нажмите «Пуск», затем «Программы» и выберите «Visual Studio 2017».  Нажмите New, затем Project, выберите Web и затем выберите ASP.NET Core Web Application. Введите название своего проекта и подтвердите.

Выберите  Web Application (Model-View-Controller) и нажмите Change Authentication

Выберите Individual User Accounts и нажмите «ОК», чтобы создать проект.



Обновление appsettings.json


В файле appsettings.json мы можем найти строку DefaultConnection Connection. Здесь, в строке соединения, измените свое имя, UID и PWD SQL Server, чтобы создать и сохранить все данные пользователя в одной базе данных.

"ConnectionStrings": {  
    "DefaultConnection": "Server= YOURSERVERNAME;Database=InventoryDB;
     user id= YOURSQLUSERID;password=YOURSQLPASSWORD;Trusted_Connection=True;
     MultipleActiveResultSets=true"  
  }, 

Шаг 3. Добавление службы идентификации в файл Startup.cs

По умолчанию в приложении ASP.NET Core служба идентификации Identity Service будет добавлена в файл Startup.cs / ConfigureServices. Вы также можете дополнительно добавить надежность пароля во время регистрации пользователей, а также установить страницу входа / выхода в систему по умолчанию, а также AccessDeniedPath, используя следующий код:

services.AddIdentity<ApplicationUser, IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders();

            //Password Strength Setting
            services.Configure<IdentityOptions>(options =>
            {
                // Password settings
                options.Password.RequireDigit = true;
                options.Password.RequiredLength = 8;
                options.Password.RequireNonAlphanumeric = false;
                options.Password.RequireUppercase = true;
                options.Password.RequireLowercase = false;
                options.Password.RequiredUniqueChars = 6;

                // Lockout settings
                options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
                options.Lockout.MaxFailedAccessAttempts = 10;
                options.Lockout.AllowedForNewUsers = true;

                // User settings
                options.User.RequireUniqueEmail = true;
            });

            //Setting the Account Login page
            services.ConfigureApplicationCookie(options =>
            {
                // Cookie settings
                options.Cookie.HttpOnly = true;
                options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
                options.LoginPath = "/Account/Login"; // If the LoginPath is not set here, 
                                                      // ASP.NET Core will default to /Account/Login
                options.LogoutPath = "/Account/Logout"; // If the LogoutPath is not set here, 
                                                        // ASP.NET Core will default to /Account/Logout
                options.AccessDeniedPath = "/Account/AccessDenied"; // If the AccessDeniedPath 
                                 // is not set here, ASP.NET Core will default to /Account/AccessDenied
                options.SlidingExpiration = true;
            });

Шаг 4. Регистрация и создание пользователей.

Теперь наше веб-приложение ASP.NET Core готово для регистрации на нашем сайте, а пользователь может войти в нашу систему после регистрации. Мы будем выполнять авторизацию, добавив роль пользователю в следующих шагах. Создайте и запустите приложение, чтобы зарегистрировать своего первого пользователя Admin по умолчанию.

Здесь мы будем регистрировать двух пользователей: одного как Admin, а другого как Manager. Мы будем использовать этих пользователей для добавления ролей. Мы создадим 2 пользователей как syedshanumcain@gmail.com и afraz@gmail.com. Примечание. Вы можете создавать пользователей в соответствии с вашими потребностями и изменять данные пользователя в стартовом коде для добавления ролей пользователям.

Обновление базы данных

Когда мы обновляем нашу базу данных, мы можем видеть, что все таблицы Identity были созданы.

Шаг 5. Создание роли и назначение пользователя для роли.

Мы используем метод ниже для создания новых ролей “Admin” и “Manager”  Мы назначим недавно зарегистрированных пользователей в качестве Admin и Manager  на нашем веб-сайте. Откройте файл Startup.cs и добавьте этот метод в файл Startup.cs.

private async Task CreateUserRoles(IServiceProvider serviceProvider)
        {
            var RoleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
            var UserManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();

            IdentityResult roleResult;
            //Adding Addmin Role  
            var roleCheck = await RoleManager.RoleExistsAsync("Admin");
            if (!roleCheck)
            {
                //create the roles and seed them to the database  
                roleResult = await RoleManager.CreateAsync(new IdentityRole("Admin"));
            }

            roleCheck = await RoleManager.RoleExistsAsync("Manager");
            if (!roleCheck)
            {
                //create the roles and seed them to the database  
                roleResult = await RoleManager.CreateAsync(new IdentityRole("Manager"));
            }

            //Assign Admin role to the main User here we have given our 
            //newly loregistered login id for Admin management  
            ApplicationUser user = await UserManager.FindByEmailAsync("syedshanumcain@gmail.com");
            var User = new ApplicationUser();
            await UserManager.AddToRoleAsync(user, "Admin");

            user = await UserManager.FindByEmailAsync("Afraz@gmail.com");
            await UserManager.AddToRoleAsync(user, "Manager");
        } 

Из файла Startup.cs мы можем найти метод Configure. Вызовите наш метод CreateUserRoles из этого метода Configure. Когда мы создаем и запускаем наше приложение, мы можем увидеть новую роль, поскольку  “Admin” и “Manager” были созданы  в таблице ASPNetRole.

Шаг 6: Создайте страницу Admin / Manager и установите авторизацию

Теперь у нас есть пользователь Admin / Manager для нашего веб-приложения ASP.NET Core в качестве следующего шага, давайте создадим контроллеры и представления  для отображения на основе входа пользователя. В нашем предыдущем примере мы уже видели, как установить авторизацию для ролей на каждой странице. Используя это, мы будем создавать все необходимые  контроллеры и представления . В прилагаемом примерном демонстрационном приложении вы можете найти все созданные нами контроллеры и представления и создать свои собственные в соответствии с вашими потребностями.

Шаг 7: Работа с Dependency Inject  для отображения меню

Создание модельного класса

Во-первых, мы начнем с создания класса в нашей папке Model. Мы указываем имя класса как MenuMaster так же, как имя нашей таблицы в нашей базе данных. В классе MenuMaster нам нужно создать такие же свойства, как наши таблицы Table, как показано ниже:

public class MenuMaster
    {
        [Key]
        public int MenuIdentity { get; set; }
        public string MenuID { get; set; }
        public string MenuName { get; set; }
        public string Parent_MenuID { get; set; }
        public string User_Roll { get; set; }
        public string MenuFileName { get; set; }
        public string MenuURL { get; set; }
        public string USE_YN { get; set; }
        public DateTime CreatedDate { get; set; }
    }


Создание класса интерфейса
Теперь пришло время создать интерфейс с помощью метода GetMenuMaster (), GetMenuMaster (String UserRole), и мы будем внедрять этот интерфейс в нашу службу, чтобы получить все данные меню из таблицы, 
а также еще один способ получить меню по роли пользователя. Для создания интерфейса добавьте новый класс в свою модельную папку и назовите класс «IMenuMasterService».

Мы изменим класс на интерфейс, поскольку мы собираемся создать интерфейс для реализации в нашем сервисе.

public interface IMenuMasterService
    {
        IEnumerable<MenuMaster> GetMenuMaster();
        IEnumerable<MenuMaster> GetMenuMaster(String UserRole);
     }

Создание сервиса
Теперь добавим новую папку «Службы» и назовем класс «MenuMasterService». В этом классе мы будем внедрять наш интерфейс IMenuMasterService. Мы знаем, что если мы реализуем интерфейс, то мы должны заявить метод интерфейса в нашем классе. В этой службе мы используем метод интерфейса, и мы возвращаем список с данными меню, а также возвращаем детали меню по роли пользователя. Мы будем непосредственно вводить это на нашу страницу просмотра.

public class MenuMasterService:IMenuMasterService
    {
        private readonly ApplicationDbContext _dbContext;

        public MenuMasterService(ApplicationDbContext dbContext)
        {
            _dbContext = dbContext;
        }

        public IEnumerable<MenuMaster> GetMenuMaster()
        { 
            return _dbContext.MenuMaster.AsEnumerable();

        } 

        public IEnumerable<MenuMaster> GetMenuMaster(string UserRole)
        {  
            var result = _dbContext.MenuMaster.Where(m => m.User_Roll == UserRole).ToList();  
            return result;
        }
    }

Регистрация сервиса
Нам необходимо зарегистрировать созданный нами сервис в контейнере. Откройте Startup.cs из вашего проекта, чтобы добавить службу в контейнер.

В классе Startup.cs найдите метод с именем ConfigureServices и добавьте службу «MenuMasterService», как показано ниже:

services.AddTransient<MenuMasterService, MenuMasterService>();

 Ввод сервиса на страницу _Layout.cshtml
Теперь это намного проще и проще, так как мы можем напрямую внедрить сервис на странице View и привязать все результаты к нашей странице просмотра. Для введения услуги в нашем представлении здесь мы будем использовать нашу существующую страницу _Layout.cshtml. Поскольку мы собираемся отобразить меню в верхней части нашего сайта и использовать его на всех наших страницах, здесь мы использовали страницу _Layout.cshtml для привязки результатов меню в виде меню на основе входа пользователя.

Здесь сначала мы проверяем, что пользователь аутентифицирован на нашем веб-сайте, а затем, если пользователь вошел в систему, мы получаем детали роли зарегистрированного пользователя и привязываем меню на основе ролей пользователя. Здесь мы связываем 2 уровня меню как Главное меню и Подменю. В нашем результате таблицы мы проверяем все Parent_MenuID = "*", поскольку мы будем отображать главное меню с parent_MenuID как «*», а в следующем внутреннем цикле мы отобразим подменю, соответствующее главному меню.

<div class="navbar-collapse collapse">
 <ul class="nav navbar-nav">
   <li><a asp-area="" asp-controller="Home" asp-action="Index">Home</a></li>
 @if (User.Identity.IsAuthenticated)
        {
            var UserRoles = "";
            if (@User.IsInRole("Admin"))
            {
                UserRoles = "Admin";
            }
            else
            {
                UserRoles = "Manager";
            }

                @if (menus.GetMenuMaster(@UserRoles).Any())
                {
                @if (menus.GetMenuMaster(@UserRoles).Any())
                {
                @foreach (var menuNames in menus.GetMenuMaster(@UserRoles).Where
                            (n => n.Parent_MenuID == "*"))
                {
                        <li>
                            <a asp-area="" asp-controller=@menuNames.MenuURL 

                               asp-action=@menuNames.MenuFileName>@menuNames.MenuName</a>
                            <ul class="sub-menu">
                                @foreach (var subMenu in menus.GetMenuMaster(@UserRoles).Where
                                         (n => n.Parent_MenuID == @menuNames.MenuID))
                                  {
                                    <li>
                                        <a asp-area="" asp-controller=@subMenu.MenuURL 

                                         asp-action=@subMenu.MenuFileName>@subMenu.MenuName</a>
                                    </li>
                                   }
                            </ul>
                            </li>
                }
                }
                }
            }
  </ul>

Точки обзора

Во-первых, создайте образец базы данных AttendanceDB на вашем SQL Server и запустите сценарий для создания таблицы MenuMaster и вставьте примеры записей. В файле appsettings.json измените строку соединения DefaultConnection с вашими подключениями SQL Server. В файле Startup.cs добавьте весь код, как мы обсуждали в этой статье. Это простое демонстрационное приложение, и мы исправили роли администратора и менеджера, вы можете изменить в соответствии с вашим требованием. Кроме того, дизайн CSS для меню и подменю не подходит для совместимости с мобильными устройствами, вы можете добавить свой собственный дизайн начальной загрузки, чтобы реализовать свои стили меню. 

No Comments

Add a Comment