冯 海

一个程序新人菜鸟的日记,希望大家多多关照。QQ:32316131

2018教程之mvc+ef + identity之七:角色权限系统菜单1

不同角色的人登录系统后,能看到不同的菜单这个这个太实用了。我还在同步思考,是不是前台也有这个问题呀,前台菜单,不同的人来可以看见不同的前台菜单哩,暂时这里只讨论后台权限菜单。

        众所周知,权限系统是每个系统里面必备的最基本的系统,然而权限系统设计有时挺麻烦的,,现在整理了下,给正在开发此模块的朋友一个思路!

  设计基础:用户、角色、权限三大核心表,加上用户角色、角色权限两个映射表(用于给用户表联系上权限表)。这样就可以通过登录的用户来获取权限列表,或判断是否拥有某个权限。

  大致用到5张表:用户表(AspNetUsers)、角色表(AspNetRoles)、菜单表(MenuInfo)、用户角色表(AspNetUserRoles)、角色菜单表(RoleMenu)。

各表的大体表结构如下:

  1、用户表(UserInfo):Id、UserName、UserPwd,......

  2、角色表(RoleInfo):Id、RoleName、......

  3、菜单表(MenuInfo):Id、MenuName、......

  4、用户角色表(UserRole):Id、UserId、RoleId

  5、角色菜单表(RoleMenu):Id、RoleId、MenuId

 最关键的地方是,某个用户登录时,如何查找该用户的菜单权限?其实一条语句即可搞定:

  假如用户的用户名为Arthur,则他的菜单权限查询如下:

  Select m.Id,m.MenuName from MenuInfo m ,UserInfo u, UserRole ur, RoleMenu rm Where m.Id = rm.MenuId and ur.RoleId = rm.RoleId and ur.UserId = u.Id and u.UserName = 'Arthur'

上面这个是SQL语句,到时我们再弄。

           任何权限的需求,都是为广义的用户分配角色,角色拥有广义的权限。角色是最重要的中枢,隐藏做幕后黑手,从不出现在业务代码里,用行话说就是解除了用户和权限的直接耦合。

  角色把用户抽象化了,几百个用户变成成几个角色,用户->角色->权限写成通用判断权限的方法:currUser.IsHave(xx权限)。核心就是一个sql联表查询语句,查询条件为用户id。

     例如:
部门权限:部门也是一种用户,建立 部门表、部门角色表。通用权限方法里加上 当前部门->部门所属角色->权限 
职位权限:职位也是一种用户,建立职位表、职位角色表,同上
菜单:也是一种权限,建立 菜单表、角色菜单表,就把菜单纳入了权限管理。通用权限方法里加上 角色列表->权限、菜单

一、五个表的模型

1.用户、角色,用户角色表都不用再建模

2.在Models下新建菜单表的模型MenuInfo.cs

 

using System.ComponentModel.DataAnnotations;

namespace MYtest2018.Models
{
	public class MenuInfo
	{

		public int Id { get; set; }
		[Display(Name = "菜单名称")]
		public string MenuName { get; set; }
		[Display(Name = "菜单地址")]
		public string MenuPath { get; set; }

		[Display(Name = "菜单图标")]
		public string MenuIcon { get; set; }
		/// <summary>
		/// 为0则为父级菜单一级菜单,否则这里刚是他选择的上级菜单的ID值
		/// </summary>
		[Display(Name = "菜单图标")]
		public int Popedomfatherid { get; set; }
		[Display(Name = "排序")]
		public int Sort { get; set; }

 
	}
}

3。 在Models下新建菜单表的模型RoleMenu.cs

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;

namespace MYtest2018.Models
{
	public class RoleMenu
	{
		public int Id { get; set; }

		[Display(Name = "角色ID")]
		public string RoleId { get; set; }
		[Display(Name = "菜单Id")]
		public int MenuId { get; set; }

		///(1为可用,2为不可用) 
		[Display(Name = "是否可用")]
		public  int IsAvailable { get; set; }






}
}

 4,在上下文中引用好code frist建表。

在DAL下的MyDALContent上下文中,增加这二个表的引用

using System.Data.Entity;

namespace MYtest2018.DAL
{
	public class MyDALContent : DbContext
	{
		/// <summary>
		/// 连接
		/// </summary>
		public MyDALContent() : base("Mytest2018") { }

		public System.Data.Entity.DbSet<MYtest2018.Models.Department> Departments { get; set; }
		public System.Data.Entity.DbSet<MYtest2018.Models.RoleMenu> RoleMenus { get; set; }
		public System.Data.Entity.DbSet<MYtest2018.Models.MenuInfo> MenuInfos { get; set; }


	}
}

  

二。创建菜单管理列表

 为了方便,我是删了数据,让他重新code first新建的表,我使用了我们上单的 install,自动建Super用户,同时就建好了所有的表表。

三、Account控制器中新建listMenu控制器并新建视图

效果图如下

 

 

 

 

在右边可以直接新建菜单不选择表示一级,选择了表示有二级,注意,因为使用bind,同时有模型验证,要是直接将一级菜单读成下拉是不行的,得给他新建一个不选择时为0的selected

			var menus = db.MenuInfos.Where(m => m.Popedomfatherid == 0).OrderBy(x => x.Sort).Select(g => new SelectListItem
			{
				Text = g.MenuName,
				Value = g.Id.ToString(),
				Selected = false
			}).ToList();
			
			menus.Insert(0, new SelectListItem { Value = "0", Text = "请选择", Selected = true });
			ViewBag.menuInfo = menus;

  

三、整个后台的源码

/// <summary>
		/// 菜单列表
		/// </summary>
		/// <param name="disposing"></param>
		[AllowAnonymous]
		[HttpGet]
		public ActionResult ListMenu(string SeachColumnString)
		{
			///读出所有的一级菜单
			ViewBag.drolistmenu = db.MenuInfos.Where(m => m.Popedomfatherid == 0).OrderBy(x => x.Sort);
			///读出所有的现有的菜单名称,以下拉框的形式写入。

			var menus = db.MenuInfos.Where(m => m.Popedomfatherid == 0).OrderBy(x => x.Sort).Select(g => new SelectListItem
			{
				Text = g.MenuName,
				Value = g.Id.ToString(),
				Selected = false
			}).ToList();
			menus.Insert(0, new SelectListItem { Value = "0", Text = "请选择", Selected = true });
			ViewBag.menuInfo = menus;

			///下面是开始显示菜单的列表了
			///读出所有的菜单列表
			var data = db.MenuInfos.ToList();
			///定义一个变量result的MenuInfo列表变量
			var result = new List<MenuInfo>();
			///读出所有的一级菜单
			var level0 = data.Where(m => m.Popedomfatherid == 0).ToList();
			///当一级菜单索引选择有的时候,一级菜单就仅为我们选择的这个
			
			if (!string.IsNullOrEmpty(SeachColumnString))
			{
				var xxx = int.Parse(SeachColumnString);
				level0 = level0.Where(m => m.Id == xxx).ToList();
			}

			///对所有一级菜单进行一次循环。 foreah (var xx in level0) 这种一样
			level0.ForEach(item =>
			{
				///定义一个children字菜单变量,当他的Popedomfatherid=当前循环的ID,取出当前的所有字菜单
				var children = data.Where(m => m.Popedomfatherid == item.Id).ToList();
				///给子菜单名字前面加上几个---
				children.ForEach(m => m.MenuName = "------------" + m.MenuName);
				///为新定义的result变量增加一个 一级菜单
				result.Add(item);
				///为新定义的result变量增加一个 所有的字菜单
				result.AddRange(children);
			});
			///ViewBag.list传值
			ViewBag.List = result;

			return View();

		}

		/// <summary>
		/// 菜单列表
		/// </summary>
		/// <param name="disposing"></param>
		[AllowAnonymous]
		[HttpPost]
		[ValidateAntiForgeryToken]
		public async Task<ActionResult> ListMenu([Bind(Include = "MenuName,MenuPath,MenuIcon,MethodName,ControllerName,Popedomfatherid,Sort")] MenuInfo model)
		{
		 
			if (ModelState.IsValid)
			{
				 
				db.MenuInfos.Add(model);
				await db.SaveChangesAsync();
				return RedirectToAction("ListMenu");


			}
			
			///读出所有的现有的菜单名称,以下拉框的形式写入。

			var menus = db.MenuInfos.Where(m => m.Popedomfatherid == 0).OrderBy(x => x.Sort).Select(g => new SelectListItem
			{
				Text = g.MenuName,
				Value = g.Id.ToString(),
				Selected = false
			}).ToList();
			
			menus.Insert(0, new SelectListItem { Value = "0", Text = "请选择", Selected = true });
			ViewBag.menuInfo = menus;
			///读出所有的一级菜单
			ViewBag.drolistmenu = db.MenuInfos.Where(m => m.Popedomfatherid == 0).OrderBy(x => x.Sort);

			return View(model);

		}

  

五、整个前台的源码

@using MYtest2018.Models
@model MenuInfo

@{
	ViewBag.Title = "ListMenu";
	Layout = "~/Views/Shared/_Layoutadmin.cshtml";
}

<div class="row wrapper border-bottom white-bg page-heading">
	<div class="col-sm-4">
		<h2>菜单管理</h2>

	</div>
	<div class="col-sm-8">
		<div class="title-action">

		</div>
	</div>
</div>

<div class="wrapper wrapper-content animated fadeInRight">

	<div class="row">
		<div class="col-lg-8">
			<div class="ibox float-e-margins">
				<div class="ibox-title">
					<h3>一级菜单列表</h3>
					<div class="form-group">
						<div class="input-group">
							<ul class="nav nav-pills nav-stacked" style="float:left;">
								@foreach (MYtest2018.Models.MenuInfo data1 in (ViewBag.drolistmenu as IEnumerable<MYtest2018.Models.MenuInfo>))
								{

									<li class="titlesize" style="float:left;">
										<a href="~/Account/ListMenu?SeachColumnString=@data1.Id"><span class="glyphicon glyphicon glyphicon-th-large" aria-hidden="true"></span> @data1.MenuName</a>

									</li>
								}
							</ul>
							</div>
					</div>
				</div>
				<div class="ibox-content p-md">

				 
					@{

						var data = ViewBag.List as List<MenuInfo>;
					}
					<div class="table-responsive">
						<table class="table table-hover issue-tracker">
							<tbody>
								@if (data != null && data.Any())
								{
									foreach (var item in data)
									{
								    <tr>
									<td>
										 @item.Id 
									</td>
									<td class="issue-info">
										<i class="@item.MenuIcon"></i> @item.MenuName
									</td>
									<td>@item.ControllerName/@item.MethodName</td>
									<td>
										<a class="btn btn-xs btn-white" href="~/Account/DelMenuInfo/@item.Id" onclick="return confirm('你确认删除吗?')"><i class="fa fa-bank"></i> 删除 </a>
										<a class="btn btn-xs btn-white" href="~/Account/EditMenuInfo/@item.Id"><i class="fa fa-edit"></i> 编辑</a>

									</td>
								</tr>
									}
								}
							</tbody>
                         </table>
                    </div>
					</div>
				</div>



		 </div>

		<div class="col-lg-4">
			<div class="ibox float-e-margins">
				<div class="ibox-content  p-md">
					<h4 class="m-b-xxs">新建菜单</h4>
					@using (Html.BeginForm("ListMenu", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
					{
						@Html.AntiForgeryToken()
						@Html.ValidationSummary("", new { @class = "text-danger" })

						<div class="form-group">
							@Html.LabelFor(m => m.Popedomfatherid, new { @class = "col-md-2 control-label" })
							<div class="col-md-10">
								@Html.DropDownList("Popedomfatherid", new SelectList(ViewBag.menuInfo, "Value", "Text"))

								@*@Html.EditorFor(model => model.BossClass, new { htmlAttributes = new { @class = "form-control" } })*@
								@Html.ValidationMessageFor(model => model.Popedomfatherid, "", new { @class = "text-danger" })

							</div>
						</div>
						<div class="form-group">
							@Html.LabelFor(m => m.MenuName, new { @class = "col-md-2 control-label" })
							<div class="col-md-10">
								@Html.TextBoxFor(m => m.MenuName, new { @class = "form-control" })
							</div>
						</div>
						<div class="form-group">
							@Html.LabelFor(m => m.ControllerName, new { @class = "col-md-2 control-label" })
							<div class="col-md-10">
								@Html.TextBoxFor(m => m.ControllerName, new { @class = "form-control" })
							</div>
						</div>
						<div class="form-group">
							@Html.LabelFor(m => m.MethodName, new { @class = "col-md-2 control-label" })
							<div class="col-md-10">
								@Html.TextBoxFor(m => m.MethodName, new { @class = "form-control" })
							</div>
						</div>
						<div class="form-group">
							@Html.LabelFor(m => m.MenuIcon, new { @class = "col-md-2 control-label" })
							<div class="col-md-10">
								@Html.TextBoxFor(m => m.MenuIcon, new { @class = "form-control" })
							</div>
						</div>
						<div class="form-group">
							@Html.LabelFor(m => m.Sort, new { @class = "col-md-2 control-label" })
							<div class="col-md-10">
								@Html.TextBoxFor(m => m.Sort, new { @class = "form-control" })
							</div>
						</div>
						<div class="form-group">
							<div class="col-md-offset-2 col-md-10">
								<input type="submit" class="btn btn-success" value="保存" />
							</div>
						</div>


					}


				</div>
			</div>

		</div>


	</div>


</div>

@section Scripts {
	@Scripts.Render("~/bundles/jqueryval")
}

  

 

posted @ 2018-09-03 13:08  秋天来了哟  阅读(276)  评论(0)    收藏  举报
认识就是缘份,愿天下人都快乐!
QQ: 32316131
Email: 32316131@qq.com