65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET Core 2.0 基于用户角色的动态菜单管理(使用依赖注入)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.95/5 (11投票s)

2018年4月2日

CPOL

8分钟阅读

viewsIcon

44397

downloadIcon

2045

在本篇文章中,我们将详细介绍用户登录后如何显示基于角色的动态菜单。为此,我们将创建一个 `Menu Master` 表并插入一些记录,以便根据登录用户的角色来显示菜单和链接 URL。

引言

在开始阅读本文之前,请先阅读我之前的文章

在之前的文章中,我们详细讨论了如何在 MVC 应用程序中使用 ASP.NET Core Identity 来创建用户角色并根据用户角色显示菜单。

在本篇文章中,我们将详细介绍用户登录后如何显示基于角色的动态菜单。为此,我们将创建一个 `Menu Master` 表并插入一些记录,以便根据登录用户的角色来显示菜单和链接 URL。

在这里,我们将看到如何

  • 创建默认的管理员和经理用户
  • 创建 `MenuMaster` 表并插入一些 `Admin` 和 `Manager` 角色的示例记录以显示菜单
  • 将未经验证的用户重定向到登录页面
  • 根据登录用户动态显示菜单

背景

必备组件

请确保您已在计算机上安装了所有先决条件。如果没有,请一个接一个地下载并安装它们。

  1. 首先,从此 链接 下载并安装 Visual Studio 2017
  2. SQL Server 2014 或更高版本

Using the Code

步骤 1 - 创建数据库

这与我们之前的文章是相关的;正如我们之前提到的,我们将使用一个通用数据库来存放 ASP.NET `Identity` 表和我们自己的新表。

在我们之前的文章中,我们已经解释了如何创建用户角色,而在这里,对于基于角色的菜单管理,我们需要在 ASP.NET `Roles` 表和我们的 `menu` 表之间建立一个关系表。

让我们详细了解如何创建我们的新 `Menu` 表,该表与 ASP.NET Identity 的 `AspNetRoles` 表有关系。

在这里,我们可以看到 `MenuMaster` 使用的字段

首先,我们将创建一个数据库,并在 `appsettings.json` 文件中为 `DefaultConnection` 设置连接字符串,指向我们的新数据库连接。我们将使用此数据库来创建 ASP.NET Core Identity 表。

创建数据库

运行以下脚本来创建我们的数据库 `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

在这里,我们可以看到我们在 `Menu Master` 表中用于根据用户角色显示菜单的记录的格式。

  • `MenuID = 'AUSER'` (我们将给出唯一的菜单 ID)。
  • `MenuName = 'ADMIN Dashboard'` (我们将给出菜单显示文本),
  • `Parent_MenuID = '*'` (如果这是主菜单,那么我们将在这里给出“`*`”,否则我们将给出前一条记录的 `MenuID` 以显示此记录作为子菜单)。
  • `User_Roll = 'ADMIN'` (在这里,我们将给出用户角色,如果同一菜单需要用于多个角色的用户,例如 `Admin`、`Manager`、`Accountant` 等,那么我们将插入相同的菜单详细信息,但具有不同的用户角色。在我们的示例中,我们为 `Admin` 和 `Manager` 用户添加了相同的菜单详细信息,因为两者都可以查看菜单和页面)。
  • `MenuFileName = 'INDEX'` (在这里,我们给出点击菜单时要显示的 `View` 名称)。
  • `MenuURL = 'ADMINC'` (在这里,我们给出点击菜单时要显示的 `Controller` 名称)。
  • `USE_YN = 'Y'` (这是一个可选字段,因为我们可以使用它来显示菜单或不显示)。
  • `CreatedDate = getDate()` (这也可选,用于输入创建日期)。

在此演示应用程序中,我们已经拥有了用户点击菜单时要显示的所有必需的控制器和视图。

步骤 2 - 创建您的 ASP.NET Core

安装 Visual Studio 2017 后,点击开始,然后选择程序,再选择 Visual Studio 2017 - 点击 Visual Studio 2017。点击新建,然后点击项目,选择 Web,然后选择 ASP.NET Core Web Application。输入您的项目名称,然后点击。

选择 Web Application (Model-View-Controller) 并点击 Change Authentication。

选择 Individual User Accounts 并点击 OK 来创建您的项目。

更新 appsettings.json

在 `appsettings.json` 文件中,我们可以找到 `DefaultConnection` 连接字符串。在这里,在连接字符串中,更改您的 SQL Server 名称、UID 和 PWD 以便在一个数据库中创建和存储所有用户详细信息。

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

步骤 3 - 在 Startup.cs 文件中添加 Identity 服务

默认情况下,在您的 ASP.NET Core 应用程序中,Identity 服务将添加在 `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 Web 应用程序已准备就绪,用户可以注册我们的网站,用户也可以在注册后登录我们的系统。我们将在下一步通过为用户添加角色来进行授权。构建并运行您的应用程序以注册您的第一个默认管理员用户。

在这里,我们将注册两个用户,一个作为 `Admin`,另一个作为 `Manager`。我们将使用这些用户来添加角色。我们将创建两个用户:syedshanumcain@gmail.comafraz@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` 方法。从 `Configure` 方法中调用我们的 `CreateUserRoles` 方法。当我们构建并运行我们的应用程序时,我们可以在 `ASPNetRole` 表中看到新创建的“`Admin`”和“`Manager`”角色。

步骤 6:创建管理员/经理页面并设置授权

现在我们已经为我们的 ASP.NET Core Web 应用程序拥有了管理员/经理用户,下一步,让我们创建控制器和视图来根据用户登录进行显示。在我们之前的示例中,我们已经看到了如何在每个页面上为角色设置授权,利用这一点,我们将创建所有必需的控制器和视图。在随附的示例演示应用程序中,您可以找到我们创建的所有控制器和视图,并根据您的需要创建您自己的。

步骤 7:使用依赖注入来显示菜单

创建模型类

首先,我们将创建一个类放在我们的 `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; }
    }

创建接口类

现在,是时候创建一个 `interface` 了,其中包含名为 `GetMenuMaster()`、`GetMenuMaster(String UserRole)` 的方法,我们将在我们的 `Service` 中实现这个 `interface` 来从表中获取所有 `Menu` 详细信息,以及另一个根据用户角色获取菜单的方法。要创建 `Interface`,请向您的 `model` 文件夹添加一个新类,并将类命名为“`IMenuMasterService`”。

我们将类更改为 `interface`,因为我们将创建一个 `interface` 来在我们的服务中实现。

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

创建服务

现在,让我们在 `Services` 文件夹中添加一个新类,并将类命名为“`MenuMasterService`”。在这个类中,我们将实现我们的 `interface IMenuMasterService`。我们知道,如果实现 `interface`,那么我们必须在我们的类中声明 `interface` 方法。在这个服务中,我们使用 `interface` 方法,并返回带有 `Menu` 详细信息的列表,以及根据用户角色返回 `Menu` 详细信息。我们将直接将此注入到我们的 View 页面。

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 页面中注入服务,并将所有结果绑定到我们的 View 页面。要在我们的 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>

关注点

首先,在您的 SQL Server 中创建一个名为 `AttendanceDB` 的示例数据库,并运行脚本来创建 `MenuMaster` 表并插入示例记录。在 `appsettings.json` 文件中,更改 `DefaultConnection` 连接字符串以匹配您的 SQL Server 连接。在 `Startup.cs` 文件中,添加本文中讨论的所有代码。这是一个简单的演示应用程序,我们已将其固定为 `Admin` 和 `Manager` 角色,您可以根据您的需求进行更改,并且菜单和子菜单的 CSS 设计不适用于移动设备,您可以添加自己的 bootstrap 设计来实现您的菜单样式。希望大家喜欢这篇文章,很快我们将看到另一篇带有更多实际示例的文章。

历史

  • ASPNETCORERoleManagement - 2018-04-03
© . All rights reserved.