前言
- 这一篇我们将完成系统的权限设置功能以及不同角色用户登录系统后动态加载菜单。注意:此示例权限只针对菜单级,如果园友需要更复杂的系统权限设置,可以拓展到按钮级或属性级。
- 用户的登录采用Form认证来实现,这样可以有效地防止非授权用户或页面链接对系统造成不安全的操作。
权限设置模块
- 页面采用角色列表和菜单列表勾选的方式,即选择角色后勾选可以操作的菜单,这样具有才角色的用户就具有操作这些菜单的权限。界面设置如下:
- 界面选择的roleID和menuID我们采用字符串的方式进行拼接。在controller中采用object类型进行接收,然后进行转化后就可以得到传入的值。权限设置的参考代码如下:
public bool SetPermit(object RoleID, object MenuIDs)
{
try
{
string[] roleArr = RoleID as string[];
long roleID = Convert.ToInt64(roleArr[].ToString()); S_Role role = context.S_Roles.Where(x => x.ID.Equals(roleID)).FirstOrDefault(); //获取角色
role.S_Menus = new List<S_Menu>(); //删除先前设置的roleID的数据
List<S_Menu> listdate = context.S_Roles.Where(x => x.ID.Equals(roleID)).FirstOrDefault().S_Menus.ToList();
foreach (var item in listdate)
{
role.S_Menus.Remove(item);
} //写入现有的数据
string[] MenuArr = MenuIDs as string[];
string[] MenuArrString = MenuArr[].ToString().TrimEnd(',').Split(',').ToArray();
List<long> arr = new List<long>();
foreach (var item in MenuArrString)
{
arr.Add(Convert.ToInt64(item));
} //必须转化为list集合,否则会出现“已有打开的与此 Command 相关联的 DataReader,必须首先将它关闭”错误
List<S_Menu> query = (from m in context.S_Menus where arr.Contains(m.ID) select m).ToList(); foreach (S_Menu menu in query)
{
role.S_Menus.Add(menu);
menu.S_Roles = new List<S_Role>();
menu.S_Roles.Add(role);
} //EF默认启用了事务提交
context.SaveChanges();
return true;
}
catch
{
return false;
}
}
- 由于想要在权限设置成功后能够反映角色拥有操作哪些菜单的权限,因此,我们需要对角色的easyui-datagrid追加点击事件,并且异步加载具有的菜单权限。Easyui-Datagrid本身具有一个很有用的数据方法unselectAll(取消选中当前页所有的行)。但需要放置在选中的菜单权限之前。参考代码如下:
$('#dg').datagrid({
onClickRow: function (index, data) {
var row = $('#dg').datagrid('getSelected');
if (row) {
var RoleID = row.ID;
$.ajax({
url: '/System/GetPermit',
type: 'POST',
data: { RoleID: RoleID },
success: function (data) {
$('#dgMenu').treegrid('unselectAll'); //重新加载 $('#dgMenu').treegrid({
onLoadSuccess: function (dataaa) {
$.each(data, function (index, item) {
$('#dgMenu').treegrid('selectRow', item); //选中设置的权限
});
}});
}
})}} });
系统登录用户获取菜单操作权限
- 在我们把权限设置模块完成后就可以使不同角色的用户登录系统后操作不同的菜单权限。由于菜单采用的是easyui-tree来绑定的数据,所以我们需要定义一个符合easyui-tree属性的数据模型,这样就可以序列化easyui-tree识别的json数据格式呢。(这和之前的easyui-treegrid使用方式是一样的)。参考代码如下:
public class mod_S_RoleMenuTree
{
public long id { get; set; } // 节点的ID
public string text { get; set; } //节点显示的文字
public string iconCls { get; set; }
public string url { get; set; }
public int treelevel { get; set; }
//节点状态,有两个值 'open' or 'closed', 默认为'open'. 当为‘closed’时说明此节点下有子节点否则此节点为叶子节点
public string state { get; set; }
public List<mod_S_RoleMenuTree> children { get; set; }// 子节点集合
}
- 在MainController中我们可以根据登录的用户名获取该用户角色所具有的菜单权限。由于此示例的菜单只设置了两级,所以没有做递归。如果需要多级菜单,可以参照上一篇文章将以下方法修改成递归方法,参考代码如下:
public ActionResult GetRoleMenus()
{
string strUser = System.Web.HttpContext.Current.User.Identity.Name;
List<S_Menu> listData = IS_Role.GetRoleMenus(strUser); var listDataParent = listData.Where(x => x.PID.Equals(null)).OrderBy(x => x.SerialNO); List<mod_S_RoleMenuTree> DataModel = new List<mod_S_RoleMenuTree>(); foreach (var item in listDataParent)
{
mod_S_RoleMenuTree model = new mod_S_RoleMenuTree();
model.id = item.ID;
model.text = item.MenuName;
model.iconCls = item.Icon;
model.state = "open";
model.url = item.Link;
model.treelevel = item.Level;
model.children = new List<mod_S_RoleMenuTree>(); var children = listData.Where(x => x.PID.Equals(item.ID)).OrderBy(x => x.SerialNO);
foreach (var childitem in children)
{
mod_S_RoleMenuTree childmodel = new mod_S_RoleMenuTree();
childmodel.id = childitem.ID;
childmodel.text = childitem.MenuName;
childmodel.iconCls = childitem.Icon;
childmodel.state = "open";
childmodel.url = childitem.Link;
model.treelevel = childitem.Level;
model.children.Add(childmodel);
} DataModel.Add(model);
} return Json(DataModel, JsonRequestBehavior.AllowGet);
}
- 再将MainController中的Index视图中的获取菜单数据的代码替换成以下代码,这样我们可以动态从数据库中读取菜单,而不是直接读取json文件。
<ul class="easyui-tree" id="txt"
data-options="url:'/Main/GetRoleMenus',method:'get',animate:true,lines:true"></ul>
登录功能
- 我们为系统设置了连个账户admin\Jack,admin具有管理员角色,Jack具有操作员角色,因此两个用户登录后看到的菜单是不一样的。用户登录参考代码如下:
[HttpPost]
public ActionResult Login(mod_Account model)
{
if (null != model){
if (IS_User.Login(model.UserName, DESEncrypt.Encrypt(model.UserPwd))){
System.Web.Security.FormsAuthentication.SetAuthCookie(model.UserName, false);
return RedirectToAction("Index", "Main");
}
else{
return View();
}
}
else{
return View();
}
}
- 由于采用Form认证,所以我们还需要在配置文件中修改一下代码:
<authentication mode="Forms">
<forms loginUrl="/Account/Login" timeout="" protection="All" />
</authentication>
<authorization>
<deny users="?"/>
</authorization>
- 退出时,需要注销认证用户,参考代码如下:
public ActionResult LoginOut()
{
System.Web.Security.FormsAuthentication.SignOut();
return RedirectToAction("Login", "Account");
}
- 到此,我们完成了此示例的基本功能模块,本示例源码已放置网盘,点此下载。不同用户登录系统显示的页面结果如下: